diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 14 | ||||
-rw-r--r-- | src/bank-lib/bank_api_context.c | 2 | ||||
-rw-r--r-- | src/bank-lib/bank_api_json.h | 4 | ||||
-rw-r--r-- | src/exchange-lib/Makefile.am | 62 | ||||
-rw-r--r-- | src/exchange-lib/afl-generate.sh | 34 | ||||
-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.c | 254 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_common.c | 194 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_common.h | 41 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_context.c | 537 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_context.h | 169 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_deposit.c | 569 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_deposit_wtid.c | 379 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_handle.c | 902 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_handle.h | 59 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_json.c | 525 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_json.h | 352 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_refresh.c | 2061 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_refresh_link.c | 482 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_reserve.c | 930 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_wire.c | 620 | ||||
-rw-r--r-- | src/exchange-lib/exchange_api_wire_deposits.c | 284 | ||||
-rw-r--r-- | src/exchange-lib/test-exchange-home/config/mint-common.conf | 30 | ||||
-rw-r--r-- | src/exchange-lib/test-exchange-home/config/mint-keyup.conf | 86 | ||||
-rw-r--r-- | src/exchange-lib/test-exchange-home/master.priv (renamed from src/mint-lib/test-mint-home/master.priv) | 0 | ||||
-rw-r--r-- | src/exchange-lib/test-exchange-home/sepa.json (renamed from src/mint-lib/test-mint-home/sepa.json) | 0 | ||||
-rw-r--r-- | src/exchange-lib/test_exchange_api.c | 2599 | ||||
-rw-r--r-- | src/exchange-tools/Makefile.am | 81 | ||||
-rw-r--r-- | src/exchange-tools/taler-auditor-sign.c | 321 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-dbinit.c | 105 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-keycheck.c | 247 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-keyup.c | 1039 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-reservemod.c | 206 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-sepa.c | 163 | ||||
-rw-r--r-- | src/exchange/.gitignore | 6 | ||||
-rw-r--r-- | src/exchange/Makefile.am | 59 | ||||
-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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 339 -> 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) | bin | 389 -> 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) | bin | 309 -> 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) | bin | 115 -> 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) | bin | 307 -> 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) | bin | 23 -> 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) | bin | 364 -> 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) | bin | 323 -> 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) | bin | 375 -> 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) | bin | 121 -> 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) | bin | 290 -> 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) | bin | 341 -> 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) | bin | 285 -> 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) | bin | 299 -> 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) | bin | 293 -> 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) | bin | 308 -> 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) | bin | 224 -> 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) | bin | 323 -> 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) | bin | 361 -> 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) | bin | 349 -> 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) | bin | 287 -> 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) | bin | 243 -> 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) | bin | 304 -> 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) | bin | 343 -> 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) | bin | 144 -> 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) | bin | 293 -> 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) | bin | 298 -> 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) | bin | 344 -> 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) | bin | 393 -> 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) | bin | 360 -> 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) | bin | 299 -> 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) | bin | 257 -> 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) | bin | 321 -> 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) | bin | 339 -> 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) | bin | 251 -> 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) | bin | 288 -> 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) | bin | 384 -> 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) | bin | 333 -> 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) | bin | 324 -> 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) | bin | 148 -> 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) | bin | 366 -> 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) | bin | 241 -> 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) | bin | 330 -> 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) | bin | 360 -> 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) | bin | 304 -> 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) | bin | 288 -> 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) | bin | 339 -> 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) | bin | 237 -> 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) | bin | 121 -> 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) | bin | 315 -> 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) | bin | 85 -> 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) | bin | 316 -> 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) | bin | 371 -> 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) | bin | 237 -> 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) | bin | 317 -> 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) | bin | 271 -> 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) | bin | 335 -> 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) | bin | 292 -> 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) | bin | 49 -> 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) | bin | 235 -> 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) | bin | 329 -> 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) | bin | 249 -> 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) | bin | 145 -> 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) | bin | 145 -> 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) | bin | 145 -> 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) | bin | 95 -> 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) | bin | 188 -> 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) | bin | 145 -> 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) | bin | 110 -> 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) | bin | 145 -> 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) | bin | 241 -> 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) | bin | 145 -> 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) | bin | 187 -> 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) | bin | 145 -> 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) | bin | 182 -> 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) | bin | 220 -> 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) | bin | 107 -> 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) | bin | 45 -> 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) | bin | 177 -> 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) | bin | 129 -> 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) | bin | 109 -> 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) | bin | 145 -> 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) | bin | 95 -> 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) | bin | 135 -> 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) | bin | 201 -> 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) | bin | 168 -> 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) | bin | 106 -> 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) | bin | 158 -> 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) | bin | 191 -> 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) | bin | 202 -> 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) | bin | 159 -> 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) | bin | 100 -> 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) | bin | 155 -> 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) | bin | 129 -> 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) | bin | 188 -> 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) | bin | 105 -> 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) | bin | 167 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 154 -> 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) | bin | 34273 -> 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) | bin | 34273 -> 34273 bytes | |||
-rw-r--r-- | src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov (renamed from src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59 (renamed from src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov (renamed from src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89 (renamed from src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov (renamed from src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108 (renamed from src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108 (renamed from src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110 (renamed from src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov (renamed from src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112 (renamed from src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov (renamed from src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov (renamed from src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov (renamed from src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov (renamed from src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov (renamed from src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov (renamed from src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov (renamed from src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150 (renamed from src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov (renamed from src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649 (renamed from src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov (renamed from src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148 (renamed from src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov (renamed from src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647 (renamed from src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146 (renamed from src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov (renamed from src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645 (renamed from src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov (renamed from src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144 (renamed from src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov (renamed from src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov (renamed from src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov (renamed from src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov (renamed from src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov (renamed from src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov (renamed from src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362 (renamed from src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov (renamed from src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639 (renamed from src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138 (renamed from src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov (renamed from src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136 (renamed from src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636 (renamed from src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov (renamed from src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712 (renamed from src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768 (renamed from src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825 (renamed from src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov (renamed from src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov (renamed from src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov (renamed from src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov (renamed from src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov (renamed from src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov (renamed from src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov (renamed from src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov (renamed from src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov (renamed from src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov (renamed from src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417 (renamed from src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov (renamed from src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639 (renamed from src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846 (renamed from src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov (renamed from src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055 (renamed from src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov (renamed from src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262 (renamed from src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471 (renamed from src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887 (renamed from src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov (renamed from src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094 (renamed from src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302 (renamed from src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511 (renamed from src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov (renamed from src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov (renamed from src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342 (renamed from src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550 (renamed from src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758 (renamed from src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968 (renamed from src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov (renamed from src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov (renamed from src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603 (renamed from src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov (renamed from src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov (renamed from src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov (renamed from src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov (renamed from src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507 (renamed from src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov (renamed from src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov (renamed from src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov (renamed from src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov (renamed from src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov (renamed from src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov (renamed from src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov (renamed from src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov (renamed from src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044 (renamed from src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov (renamed from src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov (renamed from src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov (renamed from src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov (renamed from src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov (renamed from src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov (renamed from src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov (renamed from src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov (renamed from src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov (renamed from src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov (renamed from src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov (renamed from src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov (renamed from src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov (renamed from src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov (renamed from src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov (renamed from src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov (renamed from src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov (renamed from src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108 (renamed from src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov (renamed from src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov (renamed from src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov (renamed from src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov (renamed from src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov (renamed from src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov (renamed from src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov (renamed from src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov (renamed from src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov (renamed from src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov (renamed from src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov (renamed from src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov (renamed from src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov (renamed from src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov (renamed from src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov (renamed from src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov (renamed from src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov (renamed from src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov (renamed from src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov (renamed from src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov (renamed from src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov (renamed from src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov (renamed from src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov (renamed from src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov (renamed from src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov (renamed from src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov (renamed from src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov (renamed from src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov (renamed from src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov (renamed from src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov (renamed from src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov (renamed from src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov (renamed from src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov (renamed from src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov (renamed from src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov (renamed from src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov (renamed from src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov (renamed from src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov (renamed from src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov (renamed from src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov (renamed from src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov (renamed from src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov (renamed from src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov (renamed from src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov (renamed from src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov (renamed from src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov (renamed from src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov (renamed from src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov (renamed from src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov (renamed from src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov (renamed from src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov (renamed from src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov (renamed from src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov (renamed from src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov (renamed from src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov (renamed from src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov (renamed from src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov (renamed from src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov (renamed from src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov (renamed from src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov (renamed from src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov (renamed from src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov (renamed from src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov (renamed from src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov (renamed from src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov (renamed from src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov (renamed from src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov (renamed from src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov (renamed from src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov (renamed from src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov (renamed from src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov (renamed from src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov (renamed from src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov (renamed from src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov (renamed from src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov (renamed from src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov (renamed from src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov (renamed from src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov (renamed from src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov (renamed from src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov (renamed from src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov (renamed from src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov (renamed from src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov (renamed from src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov (renamed from src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov (renamed from src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov) | 0 | ||||
-rw-r--r-- | src/exchange/taler-exchange-aggregator.c | 914 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 749 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.h | 128 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_admin.c | 164 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_admin.h | 46 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_db.c | 1900 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_db.h | 230 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_deposit.c | 281 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_deposit.h | 54 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_keystate.c | 1011 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_keystate.h | 163 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_mhd.c | 152 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_mhd.h | 111 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_parsing.c | 1137 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_parsing.h | 408 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_refresh.c | 911 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_refresh.h | 94 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserve.c | 186 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_reserve.h | 73 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 1177 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 469 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_test.c | 621 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_test.h | 225 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_tracking.c | 165 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_tracking.h | 65 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_validation.c | 231 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_validation.h | 76 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_wire.c | 220 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_wire.h | 82 | ||||
-rw-r--r-- | src/exchange/test-exchange-home/master.priv (renamed from src/mint/test-mint-home/master.priv) | 0 | ||||
-rw-r--r-- | src/exchange/test_taler_exchange_httpd.sh | 35 | ||||
-rw-r--r-- | src/exchange/test_taler_exchange_httpd_afl.sh | 41 | ||||
-rw-r--r-- | src/exchange/test_taler_mint_httpd.data | 48 | ||||
-rw-r--r-- | src/exchangedb/Makefile.am | 110 | ||||
-rw-r--r-- | src/exchangedb/exchangedb_keyio.c | 558 | ||||
-rw-r--r-- | src/exchangedb/exchangedb_plugin.c | 87 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb.c | 358 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_init.c | 622 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_init.h | 257 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_interpreter.c | 1998 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_interpreter.h | 1319 | ||||
-rw-r--r-- | src/exchangedb/perf_taler_exchangedb_values.h | 25 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_common.c | 162 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 4295 | ||||
-rw-r--r-- | src/exchangedb/test-exchange-db-postgres.conf | 8 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 907 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb_deposits.c | 152 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb_keyio.c | 85 | ||||
-rw-r--r-- | src/exchangedb/test_perf_taler_exchangedb.c | 182 | ||||
-rw-r--r-- | src/include/Makefile.am | 6 | ||||
-rw-r--r-- | src/include/taler_crypto_lib.h | 24 | ||||
-rw-r--r-- | src/include/taler_exchange_service.h | 1220 | ||||
-rw-r--r-- | src/include/taler_exchangedb_lib.h | 291 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 1431 | ||||
-rw-r--r-- | src/include/taler_mint_service.h | 1220 | ||||
-rw-r--r-- | src/include/taler_mintdb_lib.h | 291 | ||||
-rw-r--r-- | src/include/taler_mintdb_plugin.h | 1431 | ||||
-rw-r--r-- | src/include/taler_signatures.h | 200 | ||||
-rw-r--r-- | src/mint-lib/Makefile.am | 62 | ||||
-rw-r--r-- | src/mint-lib/afl-generate.sh | 34 | ||||
-rw-r--r-- | src/mint-lib/mint_api_admin.c | 254 | ||||
-rw-r--r-- | src/mint-lib/mint_api_common.c | 194 | ||||
-rw-r--r-- | src/mint-lib/mint_api_common.h | 41 | ||||
-rw-r--r-- | src/mint-lib/mint_api_context.c | 537 | ||||
-rw-r--r-- | src/mint-lib/mint_api_context.h | 169 | ||||
-rw-r--r-- | src/mint-lib/mint_api_deposit.c | 569 | ||||
-rw-r--r-- | src/mint-lib/mint_api_deposit_wtid.c | 379 | ||||
-rw-r--r-- | src/mint-lib/mint_api_handle.c | 902 | ||||
-rw-r--r-- | src/mint-lib/mint_api_handle.h | 59 | ||||
-rw-r--r-- | src/mint-lib/mint_api_json.c | 525 | ||||
-rw-r--r-- | src/mint-lib/mint_api_json.h | 352 | ||||
-rw-r--r-- | src/mint-lib/mint_api_refresh.c | 2061 | ||||
-rw-r--r-- | src/mint-lib/mint_api_refresh_link.c | 482 | ||||
-rw-r--r-- | src/mint-lib/mint_api_reserve.c | 930 | ||||
-rw-r--r-- | src/mint-lib/mint_api_wire.c | 620 | ||||
-rw-r--r-- | src/mint-lib/mint_api_wire_deposits.c | 284 | ||||
-rw-r--r-- | src/mint-lib/test-mint-home/config/mint-common.conf | 30 | ||||
-rw-r--r-- | src/mint-lib/test-mint-home/config/mint-keyup.conf | 86 | ||||
-rw-r--r-- | src/mint-lib/test_mint_api.c | 2599 | ||||
-rw-r--r-- | src/mint-tools/Makefile.am | 81 | ||||
-rw-r--r-- | src/mint-tools/taler-auditor-sign.c | 321 | ||||
-rw-r--r-- | src/mint-tools/taler-mint-dbinit.c | 105 | ||||
-rw-r--r-- | src/mint-tools/taler-mint-keycheck.c | 247 | ||||
-rw-r--r-- | src/mint-tools/taler-mint-keyup.c | 1039 | ||||
-rw-r--r-- | src/mint-tools/taler-mint-reservemod.c | 206 | ||||
-rw-r--r-- | src/mint-tools/taler-mint-sepa.c | 163 | ||||
-rw-r--r-- | src/mint/.gitignore | 6 | ||||
-rw-r--r-- | src/mint/Makefile.am | 59 | ||||
-rw-r--r-- | src/mint/taler-mint-aggregator.c | 914 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd.c | 749 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd.h | 128 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_admin.c | 164 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_admin.h | 46 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 1900 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.h | 230 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 281 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.h | 54 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_keystate.c | 1011 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_keystate.h | 163 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_mhd.c | 152 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_mhd.h | 111 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.c | 1137 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.h | 408 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 911 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.h | 94 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_reserve.c | 186 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_reserve.h | 73 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 1177 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 469 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_test.c | 621 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_test.h | 225 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_tracking.c | 165 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_tracking.h | 65 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_validation.c | 231 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_validation.h | 76 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_wire.c | 220 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_wire.h | 82 | ||||
-rw-r--r-- | src/mint/test_taler_mint_httpd.data | 48 | ||||
-rwxr-xr-x | src/mint/test_taler_mint_httpd.sh | 35 | ||||
-rwxr-xr-x | src/mint/test_taler_mint_httpd_afl.sh | 41 | ||||
-rw-r--r-- | src/mintdb/Makefile.am | 110 | ||||
-rw-r--r-- | src/mintdb/mintdb_keyio.c | 558 | ||||
-rw-r--r-- | src/mintdb/mintdb_plugin.c | 87 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb.c | 358 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_init.c | 622 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_init.h | 257 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_interpreter.c | 1998 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_interpreter.h | 1319 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_values.h | 25 | ||||
-rw-r--r-- | src/mintdb/plugin_mintdb_common.c | 162 | ||||
-rw-r--r-- | src/mintdb/plugin_mintdb_postgres.c | 4295 | ||||
-rw-r--r-- | src/mintdb/test-mint-db-postgres.conf | 8 | ||||
-rw-r--r-- | src/mintdb/test_mintdb.c | 907 | ||||
-rw-r--r-- | src/mintdb/test_mintdb_deposits.c | 152 | ||||
-rw-r--r-- | src/mintdb/test_mintdb_keyio.c | 85 | ||||
-rw-r--r-- | src/mintdb/test_perf_taler_mintdb.c | 182 | ||||
-rw-r--r-- | src/util/os_installation.c | 4 | ||||
-rw-r--r-- | src/util/wireformats.c | 2 | ||||
-rw-r--r-- | src/wire/plugin_wire_sepa.c | 4 | ||||
-rw-r--r-- | src/wire/plugin_wire_template.c | 4 | ||||
-rw-r--r-- | src/wire/plugin_wire_test.c | 4 | ||||
-rw-r--r-- | src/wire/test_sepa_wireformat.c | 2 |
2272 files changed, 39769 insertions, 39761 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ac839d52a..37c902e65 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,16 +3,24 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include if HAVE_POSTGRESQL PQ_DIR = pq endif +if HAVE_LIBCURL + BANK_LIB = bank-lib +else +if HAVE_LIBGNURL + BANK_LIB = bank-lib +endif +endif + if WALLET_ONLY SUBDIRS = include util else -SUBDIRS = include util $(PQ_DIR) bank-lib wire mintdb mint mint-tools +SUBDIRS = include util $(PQ_DIR) $(BANK_LIB) wire exchangedb exchange exchange-tools if HAVE_LIBCURL - SUBDIRS += mint-lib + SUBDIRS += exchange-lib else if HAVE_LIBGNURL - SUBDIRS += mint-lib + SUBDIRS += exchange-lib endif endif diff --git a/src/bank-lib/bank_api_context.c b/src/bank-lib/bank_api_context.c index a47b4072a..2e4083cae 100644 --- a/src/bank-lib/bank_api_context.c +++ b/src/bank-lib/bank_api_context.c @@ -390,7 +390,7 @@ TALER_BANK_fini (struct TALER_BANK_Context *ctx) /** * Obtain the URL to use for an API request. * - * @param h the mint handle to query + * @param h the exchange handle to query * @param path Taler API path (i.e. "/reserve/withdraw") * @return the full URI to use with cURL */ diff --git a/src/bank-lib/bank_api_json.h b/src/bank-lib/bank_api_json.h index 2ecaf8ef1..92fe0b1d4 100644 --- a/src/bank-lib/bank_api_json.h +++ b/src/bank-lib/bank_api_json.h @@ -14,7 +14,7 @@ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> */ /** - * @file mint-lib/mint_api_json.h + * @file exchange-lib/exchange_api_json.h * @brief functions to parse incoming requests (JSON snippets) * @author Florian Dold * @author Benedikt Mueller @@ -349,4 +349,4 @@ BAJ_spec_rsa_signature (const char *name, -/* end of mint_api_json.h */ +/* end of exchange_api_json.h */ diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am new file mode 100644 index 000000000..f5e58b401 --- /dev/null +++ b/src/exchange-lib/Makefile.am @@ -0,0 +1,62 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = \ + libtalerexchange.la + +libtalerexchange_la_LDFLAGS = \ + -version-info 0:0:0 \ + -no-undefined + +libtalerexchange_la_SOURCES = \ + exchange_api_common.c exchange_api_common.h \ + exchange_api_context.c exchange_api_context.h \ + exchange_api_json.c exchange_api_json.h \ + exchange_api_handle.c exchange_api_handle.h \ + exchange_api_admin.c \ + exchange_api_deposit.c \ + exchange_api_deposit_wtid.c \ + exchange_api_refresh.c \ + exchange_api_refresh_link.c \ + exchange_api_reserve.c \ + exchange_api_wire.c \ + exchange_api_wire_deposits.c + +libtalerexchange_la_LIBADD = \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + +if HAVE_LIBCURL +libtalerexchange_la_LIBADD += -lcurl +else +if HAVE_LIBGNURL +libtalerexchange_la_LIBADD += -lgnurl +endif +endif + +check_PROGRAMS = \ + test_exchange_api + +TESTS = \ + $(check_PROGRAMS) + +test_exchange_api_SOURCES = \ + test_exchange_api.c +test_exchange_api_LDADD = \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil \ + -ljansson + +EXTRA_DIST = \ + test-exchange-home/config/exchange-common.conf \ + test-exchange-home/master.priv \ + test-exchange-home/denomkeys/ \ + test-exchange-home/signkeys/ diff --git a/src/exchange-lib/afl-generate.sh b/src/exchange-lib/afl-generate.sh new file mode 100644 index 000000000..6ae833087 --- /dev/null +++ b/src/exchange-lib/afl-generate.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# This file is part of TALER +# Copyright (C) 2015 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +# +# +# This will generate testcases in a directory 'afl-tests', which can then +# be moved into src/exchange/afl-tests/ to be run during exchange-testing. +# +# This script uses American Fuzzy Loop (AFL) to fuzz the exchange to +# automatically create tests with good coverage. You must install +# AFL and set AFL_HOME to the directory where AFL is installed +# before running. Also, a directory "baseline/" should exist with +# templates for inputs for AFL to fuzz. These can be generated +# by running wireshark on loopback while running 'make check' in +# this directory. Save each HTTP request to a new file. +# +# Note that you want to switch 'TESTRUN = NO' and pre-init the +# database before running this, otherwise it will be awfully slow. +# +# Must be run from this directory. +# +$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-exchange-httpd -f /tmp/afl-input -d test-exchange-home/ -C diff --git a/src/mint-lib/baseline/admin_add_incoming.req b/src/exchange-lib/baseline/admin_add_incoming.req index 677678b5d..677678b5d 100644 --- a/src/mint-lib/baseline/admin_add_incoming.req +++ b/src/exchange-lib/baseline/admin_add_incoming.req diff --git a/src/mint-lib/baseline/deposit.req b/src/exchange-lib/baseline/deposit.req index f50d83e40..f50d83e40 100644 --- a/src/mint-lib/baseline/deposit.req +++ b/src/exchange-lib/baseline/deposit.req diff --git a/src/mint-lib/baseline/keys.req b/src/exchange-lib/baseline/keys.req index a9503a864..a9503a864 100644 --- a/src/mint-lib/baseline/keys.req +++ b/src/exchange-lib/baseline/keys.req diff --git a/src/mint-lib/baseline/refresh_link.req b/src/exchange-lib/baseline/refresh_link.req index acf3dff51..acf3dff51 100644 --- a/src/mint-lib/baseline/refresh_link.req +++ b/src/exchange-lib/baseline/refresh_link.req diff --git a/src/mint-lib/baseline/refresh_melt.req b/src/exchange-lib/baseline/refresh_melt.req index 98b5b6389..98b5b6389 100644 --- a/src/mint-lib/baseline/refresh_melt.req +++ b/src/exchange-lib/baseline/refresh_melt.req diff --git a/src/mint-lib/baseline/refresh_reveal.req b/src/exchange-lib/baseline/refresh_reveal.req index 3fb143960..3fb143960 100644 --- a/src/mint-lib/baseline/refresh_reveal.req +++ b/src/exchange-lib/baseline/refresh_reveal.req diff --git a/src/mint-lib/baseline/reserve_status.req b/src/exchange-lib/baseline/reserve_status.req index 4f988f669..4f988f669 100644 --- a/src/mint-lib/baseline/reserve_status.req +++ b/src/exchange-lib/baseline/reserve_status.req diff --git a/src/mint-lib/baseline/reserve_withdraw.req b/src/exchange-lib/baseline/reserve_withdraw.req index 484950250..484950250 100644 --- a/src/mint-lib/baseline/reserve_withdraw.req +++ b/src/exchange-lib/baseline/reserve_withdraw.req diff --git a/src/mint-lib/baseline/wire.req b/src/exchange-lib/baseline/wire.req index a4f1d0749..a4f1d0749 100644 --- a/src/mint-lib/baseline/wire.req +++ b/src/exchange-lib/baseline/wire.req diff --git a/src/mint-lib/baseline/wire_sepa.req b/src/exchange-lib/baseline/wire_sepa.req index 80d3d4619..80d3d4619 100644 --- a/src/mint-lib/baseline/wire_sepa.req +++ b/src/exchange-lib/baseline/wire_sepa.req diff --git a/src/mint-lib/baseline/wire_test.req b/src/exchange-lib/baseline/wire_test.req index 684352c96..684352c96 100644 --- a/src/mint-lib/baseline/wire_test.req +++ b/src/exchange-lib/baseline/wire_test.req diff --git a/src/exchange-lib/exchange_api_admin.c b/src/exchange-lib/exchange_api_admin.c new file mode 100644 index 000000000..3dcbb80e9 --- /dev/null +++ b/src/exchange-lib/exchange_api_admin.c @@ -0,0 +1,254 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_admin.c + * @brief Implementation of the /admin/ requests of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief An admin/add/incoming Handle + */ +struct TALER_EXCHANGE_AdminAddIncomingHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * HTTP headers for the request. + */ + struct curl_slist *headers; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_AdminAddIncomingResultCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + +}; + + +/** + * Function called when we're done processing the + * HTTP /admin/add/incoming request. + * + * @param cls the `struct TALER_EXCHANGE_AdminAddIncomingHandle` + * @param eh the curl request handle + */ +static void +handle_admin_add_incoming_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_AdminAddIncomingHandle *aai = cls; + long response_code; + json_t *json; + + aai->job = NULL; + json = MAC_download_get_result (&aai->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_FORBIDDEN: + /* Access denied */ + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + aai->cb (aai->cb_cls, + response_code, + json); + json_decref (json); + TALER_EXCHANGE_admin_add_incoming_cancel (aai); +} + + +/** + * Notify the exchange that we have received an incoming transaction + * which fills a reserve. Note that this API is an administrative + * API and thus not accessible to typical exchange clients, but only + * to the operators of the exchange. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param reserve_pub public key of the reserve + * @param amount amount that was deposited + * @param execution_date when did we receive the amount + * @param wire wire details + * @param res_cb the callback to call when the final result for this request is available + * @param res_cb_cls closure for the above callback + * @return NULL + * if the inputs are invalid (i.e. invalid amount). + * In this case, the callback is not called. + */ +struct TALER_EXCHANGE_AdminAddIncomingHandle * +TALER_EXCHANGE_admin_add_incoming (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute execution_date, + const json_t *wire, + TALER_EXCHANGE_AdminAddIncomingResultCallback res_cb, + void *res_cb_cls) +{ + struct TALER_EXCHANGE_AdminAddIncomingHandle *aai; + struct TALER_EXCHANGE_Context *ctx; + json_t *admin_obj; + CURL *eh; + + GNUNET_assert (GNUNET_OK == + TALER_round_abs_time (&execution_date)); + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */ + " s:o, s:O}", /* execution_Date/wire */ + "reserve_pub", TALER_json_from_data (reserve_pub, + sizeof (*reserve_pub)), + "amount", TALER_json_from_amount (amount), + "execution_date", TALER_json_from_abs (execution_date), + "wire", wire); + aai = GNUNET_new (struct TALER_EXCHANGE_AdminAddIncomingHandle); + aai->exchange = exchange; + aai->cb = res_cb; + aai->cb_cls = res_cb_cls; + aai->url = MAH_path_to_url (exchange, "/admin/add/incoming"); + + eh = curl_easy_init (); + GNUNET_assert (NULL != (aai->json_enc = + json_dumps (admin_obj, + JSON_COMPACT))); + json_decref (admin_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + aai->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + aai->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (aai->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &aai->db)); + ctx = MAH_handle_to_context (exchange); + aai->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_admin_add_incoming_finished, + aai); + return aai; +} + + +/** + * Cancel an add incoming. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param aai the admin add incoming request handle + */ +void +TALER_EXCHANGE_admin_add_incoming_cancel (struct TALER_EXCHANGE_AdminAddIncomingHandle *aai) +{ + if (NULL != aai->job) + { + MAC_job_cancel (aai->job); + aai->job = NULL; + } + curl_slist_free_all (aai->headers); + GNUNET_free_non_null (aai->db.buf); + GNUNET_free (aai->url); + GNUNET_free (aai->json_enc); + GNUNET_free (aai); +} + + +/* end of exchange_api_admin.c */ diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c new file mode 100644 index 000000000..805c3fc4e --- /dev/null +++ b/src/exchange-lib/exchange_api_common.c @@ -0,0 +1,194 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_common.c + * @brief common functions for the exchange API + * @author Christian Grothoff + */ +#include "platform.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * Verify a coins transaction history as returned by the exchange. + * + * @param currency expected currency for the coin + * @param coin_pub public key of the coin + * @param history history of the coin in json encoding + * @param[out] total how much of the coin has been spent according to @a history + * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not + */ +int +TALER_EXCHANGE_verify_coin_history_ (const char *currency, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + json_t *history, + struct TALER_Amount *total) +{ + size_t len; + size_t off; + + if (NULL == history) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + len = json_array_size (history); + if (0 == len) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + TALER_amount_get_zero (currency, + total); + for (off=0;off<len;off++) + { + json_t *transaction; + struct TALER_Amount amount; + struct TALER_CoinSpendSignatureP sig; + void *details; + size_t details_size; + const char *type; + struct MAJ_Specification spec[] = { + MAJ_spec_amount ("amount", + &amount), + MAJ_spec_string ("type", + &type), + MAJ_spec_fixed_auto ("signature", + &sig), + MAJ_spec_varsize ("details", + &details, + &details_size), + MAJ_spec_end + }; + + transaction = json_array_get (history, + off); + if (GNUNET_OK != + MAJ_parse_json (transaction, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 == strcasecmp (type, + "DEPOSIT")) + { + const struct TALER_DepositRequestPS *dr; + struct TALER_Amount dr_amount; + + if (details_size != sizeof (struct TALER_DepositRequestPS)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + dr = (const struct TALER_DepositRequestPS *) details; + if (details_size != ntohl (dr->purpose.size)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, + &dr->purpose, + &sig.eddsa_signature, + &coin_pub->eddsa_pub)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + + // FIXME: check sig! + TALER_amount_ntoh (&dr_amount, + &dr->amount_with_fee); + if (0 != TALER_amount_cmp (&dr_amount, + &amount)) + { + GNUNET_break (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + } + else if (0 == strcasecmp (type, + "MELT")) + { + const struct TALER_RefreshMeltCoinAffirmationPS *rm; + struct TALER_Amount rm_amount; + + if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details; + if (details_size != ntohl (rm->purpose.size)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, + &rm->purpose, + &sig.eddsa_signature, + &coin_pub->eddsa_pub)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + TALER_amount_ntoh (&rm_amount, + &rm->amount_with_fee); + if (0 != TALER_amount_cmp (&rm_amount, + &amount)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + } + else + { + /* signature not supported, new version on server? */ + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_amount_add (total, + total, + &amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + MAJ_parse_free (spec); + } + return GNUNET_OK; +} + + +/* end of exchange_api_common.c */ diff --git a/src/exchange-lib/exchange_api_common.h b/src/exchange-lib/exchange_api_common.h new file mode 100644 index 000000000..49f486b00 --- /dev/null +++ b/src/exchange-lib/exchange_api_common.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_common.h + * @brief common functions for the exchange API + * @author Christian Grothoff + */ +#include <jansson.h> +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" + +/** + * Verify a coins transaction history as returned by the exchange. + * + * @param currency expected currency for the coin + * @param coin_pub public key of the coin + * @param history history of the coin in json encoding + * @param[out] total how much of the coin has been spent according to @a history + * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not + */ +int +TALER_EXCHANGE_verify_coin_history_ (const char *currency, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + json_t *history, + struct TALER_Amount *total); + +/* end of exchange_api_common.h */ diff --git a/src/exchange-lib/exchange_api_context.c b/src/exchange-lib/exchange_api_context.c new file mode 100644 index 000000000..544719001 --- /dev/null +++ b/src/exchange-lib/exchange_api_context.c @@ -0,0 +1,537 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_context.c + * @brief Implementation of the context part of the exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include "taler_exchange_service.h" +#include "exchange_api_context.h" + + +/** + * Log error related to CURL operations. + * + * @param type log level + * @param function which function failed to run + * @param code what was the curl error code + */ +#define CURL_STRERROR(type, function, code) \ + GNUNET_log (type, \ + "Curl function `%s' has failed at `%s:%d' with error: %s\n", \ + function, __FILE__, __LINE__, curl_easy_strerror (code)); + +/** + * Print JSON parsing related error information + */ +#define JSON_WARN(error) \ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ + "JSON parsing failed at %s:%u: %s (%s)\n", \ + __FILE__, __LINE__, error.text, error.source) + + +/** + * Failsafe flag. Raised if our constructor fails to initialize + * the Curl library. + */ +static int TALER_EXCHANGE_curl_fail; + + +/** + * Jobs are CURL requests running within a `struct TALER_EXCHANGE_Context`. + */ +struct MAC_Job +{ + + /** + * We keep jobs in a DLL. + */ + struct MAC_Job *next; + + /** + * We keep jobs in a DLL. + */ + struct MAC_Job *prev; + + /** + * Easy handle of the job. + */ + CURL *easy_handle; + + /** + * Context this job runs in. + */ + struct TALER_EXCHANGE_Context *ctx; + + /** + * Function to call upon completion. + */ + MAC_JobCompletionCallback jcc; + + /** + * Closure for @e jcc. + */ + void *jcc_cls; + +}; + + +/** + * Context + */ +struct TALER_EXCHANGE_Context +{ + /** + * Curl multi handle + */ + CURLM *multi; + + /** + * Curl share handle + */ + CURLSH *share; + + /** + * We keep jobs in a DLL. + */ + struct MAC_Job *jobs_head; + + /** + * We keep jobs in a DLL. + */ + struct MAC_Job *jobs_tail; + + /** + * HTTP header "application/json", created once and used + * for all requests that need it. + */ + struct curl_slist *json_header; + +}; + + +/** + * Initialise this library. This function should be called before using any of + * the following functions. + * + * @return library context + */ +struct TALER_EXCHANGE_Context * +TALER_EXCHANGE_init () +{ + struct TALER_EXCHANGE_Context *ctx; + CURLM *multi; + CURLSH *share; + + if (TALER_EXCHANGE_curl_fail) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Curl was not initialised properly\n"); + return NULL; + } + if (NULL == (multi = curl_multi_init ())) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to create a Curl multi handle\n"); + return NULL; + } + if (NULL == (share = curl_share_init ())) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to create a Curl share handle\n"); + return NULL; + } + ctx = GNUNET_new (struct TALER_EXCHANGE_Context); + ctx->multi = multi; + ctx->share = share; + GNUNET_assert (NULL != (ctx->json_header = + curl_slist_append (NULL, + "Content-Type: application/json"))); + return ctx; +} + + +/** + * Schedule a CURL request to be executed and call the given @a jcc + * upon its completion. Note that the context will make use of the + * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can + * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument + * from a valid @a eh afterwards. + * + * This function modifies the CURL handle to add the + * "Content-Type: application/json" header if @a add_json is set. + * + * @param ctx context to execute the job in + * @param eh curl easy handle for the request, will + * be executed AND cleaned up + * @param add_json add "application/json" content type header + * @param jcc callback to invoke upon completion + * @param jcc_cls closure for @a jcc + */ +struct MAC_Job * +MAC_job_add (struct TALER_EXCHANGE_Context *ctx, + CURL *eh, + int add_json, + MAC_JobCompletionCallback jcc, + void *jcc_cls) +{ + struct MAC_Job *job; + + if (GNUNET_YES == add_json) + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HTTPHEADER, + ctx->json_header)); + + job = GNUNET_new (struct MAC_Job); + job->easy_handle = eh; + job->ctx = ctx; + job->jcc = jcc; + job->jcc_cls = jcc_cls; + GNUNET_CONTAINER_DLL_insert (ctx->jobs_head, + ctx->jobs_tail, + job); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_PRIVATE, + job)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_SHARE, + ctx->share)); + GNUNET_assert (CURLM_OK == + curl_multi_add_handle (ctx->multi, + eh)); + return job; +} + + +/** + * Obtain the `jcc_cls` argument from an `eh` that was + * given to #MAC_job_add(). + * + * @param eh easy handle that was used + * @return the `jcc_cls` that was given to #MAC_job_add(). + */ +void * +MAC_easy_to_closure (CURL *eh) +{ + struct MAC_Job *job; + + GNUNET_assert (CURLE_OK == + curl_easy_getinfo (eh, + CURLINFO_PRIVATE, + (char **) &job)); + return job->jcc_cls; +} + + +/** + * Cancel a job. Must only be called before the job completion + * callback is called for the respective job. + * + * @param job job to cancel + */ +void +MAC_job_cancel (struct MAC_Job *job) +{ + struct TALER_EXCHANGE_Context *ctx = job->ctx; + + GNUNET_CONTAINER_DLL_remove (ctx->jobs_head, + ctx->jobs_tail, + job); + GNUNET_assert (CURLM_OK == + curl_multi_remove_handle (ctx->multi, + job->easy_handle)); + curl_easy_cleanup (job->easy_handle); + GNUNET_free (job); +} + + +/** + * Run the main event loop for the Taler interaction. + * + * @param ctx the library context + */ +void +TALER_EXCHANGE_perform (struct TALER_EXCHANGE_Context *ctx) +{ + CURLMsg *cmsg; + struct MAC_Job *job; + int n_running; + int n_completed; + + (void) curl_multi_perform (ctx->multi, + &n_running); + while (NULL != (cmsg = curl_multi_info_read (ctx->multi, + &n_completed))) + { + /* Only documented return value is CURLMSG_DONE */ + GNUNET_break (CURLMSG_DONE == cmsg->msg); + GNUNET_assert (CURLE_OK == + curl_easy_getinfo (cmsg->easy_handle, + CURLINFO_PRIVATE, + (char **) &job)); + GNUNET_assert (job->ctx == ctx); + job->jcc (job->jcc_cls, + cmsg->easy_handle); + MAC_job_cancel (job); + } +} + + +/** + * Obtain the information for a select() call to wait until + * #TALER_EXCHANGE_perform() is ready again. Note that calling + * any other TALER_EXCHANGE-API may also imply that the library + * is again ready for #TALER_EXCHANGE_perform(). + * + * Basically, a client should use this API to prepare for select(), + * then block on select(), then call #TALER_EXCHANGE_perform() and then + * start again until the work with the context is done. + * + * This function will NOT zero out the sets and assumes that @a max_fd + * and @a timeout are already set to minimal applicable values. It is + * safe to give this API FD-sets and @a max_fd and @a timeout that are + * already initialized to some other descriptors that need to go into + * the select() call. + * + * @param ctx context to get the event loop information for + * @param read_fd_set will be set for any pending read operations + * @param write_fd_set will be set for any pending write operations + * @param except_fd_set is here because curl_multi_fdset() has this argument + * @param max_fd set to the highest FD included in any set; + * if the existing sets have no FDs in it, the initial + * value should be "-1". (Note that `max_fd + 1` will need + * to be passed to select().) + * @param timeout set to the timeout in milliseconds (!); -1 means + * no timeout (NULL, blocking forever is OK), 0 means to + * proceed immediately with #TALER_EXCHANGE_perform(). + */ +void +TALER_EXCHANGE_get_select_info (struct TALER_EXCHANGE_Context *ctx, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *except_fd_set, + int *max_fd, + long *timeout) +{ + long to; + int m; + + m = -1; + GNUNET_assert (CURLM_OK == + curl_multi_fdset (ctx->multi, + read_fd_set, + write_fd_set, + except_fd_set, + &m)); + to = *timeout; + *max_fd = GNUNET_MAX (m, *max_fd); + GNUNET_assert (CURLM_OK == + curl_multi_timeout (ctx->multi, + &to)); + + /* Only if what we got back from curl is smaller than what we + already had (-1 == infinity!), then update timeout */ + if ( (to < *timeout) && + (-1 != to) ) + *timeout = to; + if ( (-1 == (*timeout)) && + (NULL != ctx->jobs_head) ) + *timeout = to; +} + + +/** + * Cleanup library initialisation resources. This function should be called + * after using this library to cleanup the resources occupied during library's + * initialisation. + * + * @param ctx the library context + */ +void +TALER_EXCHANGE_fini (struct TALER_EXCHANGE_Context *ctx) +{ + /* all jobs must have been cancelled at this time, assert this */ + GNUNET_assert (NULL == ctx->jobs_head); + curl_share_cleanup (ctx->share); + curl_multi_cleanup (ctx->multi); + curl_slist_free_all (ctx->json_header); + GNUNET_free (ctx); +} + + +/** + * Callback used when downloading the reply to an HTTP request. + * Just appends all of the data to the `buf` in the + * `struct MAC_DownloadBuffer` for further processing. The size of + * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if + * the download exceeds this size, we abort with an error. + * + * @param bufptr data downloaded via HTTP + * @param size size of an item in @a bufptr + * @param nitems number of items in @a bufptr + * @param cls the `struct KeysRequest` + * @return number of bytes processed from @a bufptr + */ +size_t +MAC_download_cb (char *bufptr, + size_t size, + size_t nitems, + void *cls) +{ + struct MAC_DownloadBuffer *db = cls; + size_t msize; + void *buf; + + if (0 == size * nitems) + { + /* Nothing (left) to do */ + return 0; + } + msize = size * nitems; + if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) + { + db->eno = ENOMEM; + return 0; /* signals an error to curl */ + } + db->buf = GNUNET_realloc (db->buf, + db->buf_size + msize); + buf = db->buf + db->buf_size; + memcpy (buf, bufptr, msize); + db->buf_size += msize; + return msize; +} + + +/** + * Obtain information about the final result about the + * HTTP download. If the download was successful, parses + * the JSON in the @a db and returns it. Also returns + * the HTTP @a response_code. If the download failed, + * the return value is NULL. The response code is set + * in any case, on download errors to zero. + * + * Calling this function also cleans up @a db. + * + * @param db download buffer + * @param eh CURL handle (to get the response code) + * @param[out] response_code set to the HTTP response code + * (or zero if we aborted the download, i.e. + * because the response was too big, or if + * the JSON we received was malformed). + * @return NULL if downloading a JSON reply failed + */ +json_t * +MAC_download_get_result (struct MAC_DownloadBuffer *db, + CURL *eh, + long *response_code) +{ + json_t *json; + json_error_t error; + char *ct; + + if ( (CURLE_OK != + curl_easy_getinfo (eh, + CURLINFO_CONTENT_TYPE, + &ct)) || + (NULL == ct) || + (0 != strcasecmp (ct, + "application/json")) ) + { + /* No content type or explicitly not JSON, refuse to parse + (but keep response code) */ + if (CURLE_OK != + curl_easy_getinfo (eh, + CURLINFO_RESPONSE_CODE, + response_code)) + { + /* unexpected error... */ + GNUNET_break (0); + *response_code = 0; + } + return NULL; + } + + json = NULL; + if (0 == db->eno) + { + json = json_loadb (db->buf, + db->buf_size, + JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, + &error); + if (NULL == json) + { + JSON_WARN (error); + *response_code = 0; + } + } + GNUNET_free_non_null (db->buf); + db->buf = NULL; + db->buf_size = 0; + if (NULL != json) + { + if (CURLE_OK != + curl_easy_getinfo (eh, + CURLINFO_RESPONSE_CODE, + response_code)) + { + /* unexpected error... */ + GNUNET_break (0); + *response_code = 0; + } + } + return json; +} + + +/** + * Initial global setup logic, specifically runs the Curl setup. + */ +__attribute__ ((constructor)) +void +TALER_EXCHANGE_constructor__ (void) +{ + CURLcode ret; + + if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT))) + { + CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, + "curl_global_init", + ret); + TALER_EXCHANGE_curl_fail = 1; + } +} + + +/** + * Cleans up after us, specifically runs the Curl cleanup. + */ +__attribute__ ((destructor)) +void +TALER_EXCHANGE_destructor__ (void) +{ + if (TALER_EXCHANGE_curl_fail) + return; + curl_global_cleanup (); +} + +/* end of exchange_api_context.c */ diff --git a/src/exchange-lib/exchange_api_context.h b/src/exchange-lib/exchange_api_context.h new file mode 100644 index 000000000..3c54bfe07 --- /dev/null +++ b/src/exchange-lib/exchange_api_context.h @@ -0,0 +1,169 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_context.h + * @brief Internal interface to the context part of the exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "taler_signatures.h" + + +/** + * Entry in the context's job queue. + */ +struct MAC_Job; + +/** + * Function to call upon completion of a job. + * + * @param cls closure + * @param eh original easy handle (for inspection) + */ +typedef void +(*MAC_JobCompletionCallback)(void *cls, + CURL *eh); + + +/** + * Schedule a CURL request to be executed and call the given @a jcc + * upon its completion. Note that the context will make use of the + * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can + * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument + * from a valid @a eh afterwards. + * + * This function modifies the CURL handle to add the + * "Content-Type: application/json" header if @a add_json is set. + * + * @param ctx context to execute the job in + * @param eh curl easy handle for the request, will + * be executed AND cleaned up + * @param add_json add "application/json" content type header + * @param jcc callback to invoke upon completion + * @param jcc_cls closure for @a jcc + */ +struct MAC_Job * +MAC_job_add (struct TALER_EXCHANGE_Context *ctx, + CURL *eh, + int add_json, + MAC_JobCompletionCallback jcc, + void *jcc_cls); + + +/** + * Obtain the `jcc_cls` argument from an `eh` that was + * given to #MAC_job_add(). + * + * @param eh easy handle that was used + * @return the `jcc_cls` that was given to #MAC_job_add(). + */ +void * +MAC_easy_to_closure (CURL *eh); + + +/** + * Cancel a job. Must only be called before the job completion + * callback is called for the respective job. + * + * @param job job to cancel + */ +void +MAC_job_cancel (struct MAC_Job *job); + + +/** + * @brief Buffer data structure we use to buffer the HTTP download + * before giving it to the JSON parser. + */ +struct MAC_DownloadBuffer +{ + + /** + * Download buffer + */ + void *buf; + + /** + * The size of the download buffer + */ + size_t buf_size; + + /** + * Error code (based on libc errno) if we failed to download + * (i.e. response too large). + */ + int eno; + +}; + + +/** + * Callback used when downloading the reply to an HTTP request. + * Just appends all of the data to the `buf` in the + * `struct MAC_DownloadBuffer` for further processing. The size of + * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if + * the download exceeds this size, we abort with an error. + * + * Should be used by the various routines as the + * CURLOPT_WRITEFUNCTION. A `struct MAC_DownloadBuffer` needs to be + * passed to the CURLOPT_WRITEDATA. + * + * Afterwards, `eno` needs to be checked to ensure that the download + * completed correctly. + * + * @param bufptr data downloaded via HTTP + * @param size size of an item in @a bufptr + * @param nitems number of items in @a bufptr + * @param cls the `struct KeysRequest` + * @return number of bytes processed from @a bufptr + */ +size_t +MAC_download_cb (char *bufptr, + size_t size, + size_t nitems, + void *cls); + + +/** + * Obtain information about the final result about the + * HTTP download. If the download was successful, parses + * the JSON in the @a db and returns it. Also returns + * the HTTP @a response_code. If the download failed, + * the return value is NULL. The response code is set + * in any case, on download errors to zero. + * + * Calling this function also cleans up @a db. + * + * @param db download buffer + * @param eh CURL handle (to get the response code) + * @param[out] response_code set to the HTTP response code + * (or zero if we aborted the download, i.e. + * because the response was too big, or if + * the JSON we received was malformed). + * @return NULL if downloading a JSON reply failed + */ +json_t * +MAC_download_get_result (struct MAC_DownloadBuffer *db, + CURL *eh, + long *response_code); + + +/* end of exchange_api_context.h */ diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c new file mode 100644 index 000000000..deba4877d --- /dev/null +++ b/src/exchange-lib/exchange_api_deposit.c @@ -0,0 +1,569 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_deposit.c + * @brief Implementation of the /deposit request of the exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief A Deposit Handle + */ +struct TALER_EXCHANGE_DepositHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_DepositResultCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Information the exchange should sign in response. + */ + struct TALER_DepositConfirmationPS depconf; + + /** + * Value of the /deposit transaction, including fee. + */ + struct TALER_Amount amount_with_fee; + + /** + * Total value of the coin being transacted with. + */ + struct TALER_Amount coin_value; + +}; + + +/** + * Verify that the signature on the "200 OK" response + * from the exchange is valid. + * + * @param dh deposit handle + * @param json json reply with the signature + * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not + */ +static int +verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh, + json_t *json) +{ + struct TALER_ExchangeSignatureP exchange_sig; + struct TALER_ExchangePublicKeyP exchange_pub; + const struct TALER_EXCHANGE_Keys *key_state; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("sig", &exchange_sig), + MAJ_spec_fixed_auto ("pub", &exchange_pub), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + key_state = TALER_EXCHANGE_get_keys (dh->exchange); + if (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_state, + &exchange_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT, + &dh->depconf.purpose, + &exchange_sig.eddsa_signature, + &exchange_pub.eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Verify that the signatures on the "403 FORBIDDEN" response from the + * exchange demonstrating customer double-spending are valid. + * + * @param dh deposit handle + * @param json json reply with the signature(s) and transaction history + * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not + */ +static int +verify_deposit_signature_forbidden (const struct TALER_EXCHANGE_DepositHandle *dh, + json_t *json) +{ + json_t *history; + struct TALER_Amount total; + + history = json_object_get (json, + "history"); + if (GNUNET_OK != + TALER_EXCHANGE_verify_coin_history_ (dh->coin_value.currency, + &dh->depconf.coin_pub, + history, + &total)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_amount_add (&total, + &total, + &dh->amount_with_fee)) + { + /* clearly not OK if our transaction would have caused + the overflow... */ + return GNUNET_OK; + } + + if (0 >= TALER_amount_cmp (&total, + &dh->coin_value)) + { + /* transaction should have still fit */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + /* everything OK, proof of double-spending was provided */ + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /deposit request. + * + * @param cls the `struct TALER_EXCHANGE_DepositHandle` + * @param eh the curl request handle + */ +static void +handle_deposit_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_DepositHandle *dh = cls; + long response_code; + json_t *json; + + dh->job = NULL; + json = MAC_download_get_result (&dh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + if (GNUNET_OK != + verify_deposit_signature_ok (dh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_FORBIDDEN: + /* Double spending; check signatures on transaction history */ + if (GNUNET_OK != + verify_deposit_signature_forbidden (dh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + dh->cb (dh->cb_cls, + response_code, + json); + json_decref (json); + TALER_EXCHANGE_deposit_cancel (dh); +} + + +/** + * Verify signature information about the deposit. + * + * @param dki public key information + * @param amount the amount to be deposited + * @param h_wire hash of the merchant’s account details + * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange) + * @param coin_pub coin’s public key + * @param denom_pub denomination key with which the coin is signed + * @param denom_sig exchange’s unblinded signature of the coin + * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange + * @param transaction_id transaction id for the transaction between merchant and customer + * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) + * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed) + * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. + * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not + */ +static int +verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki, + const struct TALER_Amount *amount, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_DenominationSignature *denom_sig, + const struct TALER_DenominationPublicKey *denom_pub, + struct GNUNET_TIME_Absolute timestamp, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_DepositRequestPS dr; + struct TALER_CoinPublicInfo coin_info; + + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); + dr.h_contract = *h_contract; + dr.h_wire = *h_wire; + dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + dr.transaction_id = GNUNET_htonll (transaction_id); + TALER_amount_hton (&dr.amount_with_fee, + amount); + TALER_amount_hton (&dr.deposit_fee, + &dki->fee_deposit); + dr.merchant = *merchant_pub; + dr.coin_pub = *coin_pub; + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, + &dr.purpose, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub)) + { + TALER_LOG_WARNING ("Invalid coin signature on /deposit request\n"); + { + char *s; + s = TALER_amount_to_string (amount); + TALER_LOG_DEBUG ("... amount_with_fee was %s\n", s); + GNUNET_free (s); + s = TALER_amount_to_string (&dki->fee_deposit); + TALER_LOG_DEBUG ("... deposit_fee was %s\n", s); + GNUNET_free (s); + } + + return GNUNET_SYSERR; + } + + /* check coin signature */ + coin_info.coin_pub = *coin_pub; + coin_info.denom_pub = *denom_pub; + coin_info.denom_sig = *denom_sig; + if (GNUNET_YES != + TALER_test_coin_valid (&coin_info)) + { + TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); + return GNUNET_SYSERR; + } + if (0 < TALER_amount_cmp (&dki->fee_deposit, + amount)) + { + TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Submit a deposit permission to the exchange and get the exchange's response. + * Note that while we return the response verbatim to the caller for + * further processing, we do already verify that the response is + * well-formed (i.e. that signatures included in the response are all + * valid). If the exchange's reply is not well-formed, we return an + * HTTP status code of zero to @a cb. + * + * We also verify that the @a coin_sig is valid for this deposit + * request, and that the @a ub_sig is a valid signature for @a + * coin_pub. Also, the @a exchange must be ready to operate (i.e. have + * finished processing the /keys reply). If either check fails, we do + * NOT initiate the transaction with the exchange and instead return NULL. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param amount the amount to be deposited + * @param wire_deadline date until which the merchant would like the exchange to settle the balance (advisory, the exchange cannot be + * forced to settle in the past or upon very short notice, but of course a well-behaved exchange will limit aggregation based on the advice received) + * @param wire_details the merchant’s account details, in a format supported by the exchange + * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange) + * @param coin_pub coin’s public key + * @param denom_pub denomination key with which the coin is signed + * @param denom_sig exchange’s unblinded signature of the coin + * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange + * @param transaction_id transaction id for the transaction between merchant and customer + * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) + * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed) + * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_DepositHandle * +TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute wire_deadline, + json_t *wire_details, + const struct GNUNET_HashCode *h_contract, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_DenominationSignature *denom_sig, + const struct TALER_DenominationPublicKey *denom_pub, + struct GNUNET_TIME_Absolute timestamp, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_CoinSpendSignatureP *coin_sig, + TALER_EXCHANGE_DepositResultCallback cb, + void *cb_cls) +{ + const struct TALER_EXCHANGE_Keys *key_state; + const struct TALER_EXCHANGE_DenomPublicKey *dki; + struct TALER_EXCHANGE_DepositHandle *dh; + struct TALER_EXCHANGE_Context *ctx; + json_t *deposit_obj; + CURL *eh; + struct GNUNET_HashCode h_wire; + struct TALER_Amount amount_without_fee; + + (void) TALER_round_abs_time (&wire_deadline); + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + /* initialize h_wire */ + if (GNUNET_OK != + TALER_hash_json (wire_details, + &h_wire)) + { + GNUNET_break (0); + return NULL; + } + key_state = TALER_EXCHANGE_get_keys (exchange); + dki = TALER_EXCHANGE_get_denomination_key (key_state, + denom_pub); + if (NULL == dki) + { + TALER_LOG_WARNING ("Denomination key unknown to exchange\n"); + return NULL; + } + if (GNUNET_SYSERR == + TALER_amount_subtract (&amount_without_fee, + amount, + &dki->fee_deposit)) + { + GNUNET_break (0); + return NULL; + } + + if (GNUNET_OK != + verify_signatures (dki, + amount, + &h_wire, + h_contract, + coin_pub, + denom_sig, + denom_pub, + timestamp, + transaction_id, + merchant_pub, + refund_deadline, + coin_sig)) + { + GNUNET_break_op (0); + return NULL; + } + + deposit_obj = json_pack ("{s:o, s:O," /* f/wire */ + " s:o, s:o," /* H_wire, H_contract */ + " s:o, s:o," /* coin_pub, denom_pub */ + " s:o, s:o," /* ub_sig, timestamp */ + " s:I, s:o," /* transaction id, merchant_pub */ + " s:o, s:o," /* refund_deadline, wire_deadline */ + " s:o}", /* coin_sig */ + "f", TALER_json_from_amount (amount), + "wire", wire_details, + "H_wire", TALER_json_from_data (&h_wire, + sizeof (h_wire)), + "H_contract", TALER_json_from_data (h_contract, + sizeof (struct GNUNET_HashCode)), + "coin_pub", TALER_json_from_data (coin_pub, + sizeof (*coin_pub)), + "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key), + "ub_sig", TALER_json_from_rsa_signature (denom_sig->rsa_signature), + "timestamp", TALER_json_from_abs (timestamp), + "transaction_id", (json_int_t) transaction_id, + "merchant_pub", TALER_json_from_data (merchant_pub, + sizeof (*merchant_pub)), + "refund_deadline", TALER_json_from_abs (refund_deadline), + "edate", TALER_json_from_abs (wire_deadline), + "coin_sig", TALER_json_from_data (coin_sig, + sizeof (*coin_sig)) + ); + + dh = GNUNET_new (struct TALER_EXCHANGE_DepositHandle); + dh->exchange = exchange; + dh->cb = cb; + dh->cb_cls = cb_cls; + dh->url = MAH_path_to_url (exchange, "/deposit"); + dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); + dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT); + dh->depconf.h_contract = *h_contract; + dh->depconf.h_wire = h_wire; + dh->depconf.transaction_id = GNUNET_htonll (transaction_id); + dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + TALER_amount_hton (&dh->depconf.amount_without_fee, + &amount_without_fee); + dh->depconf.coin_pub = *coin_pub; + dh->depconf.merchant = *merchant_pub; + dh->amount_with_fee = *amount; + dh->coin_value = dki->value; + + eh = curl_easy_init (); + GNUNET_assert (NULL != (dh->json_enc = + json_dumps (deposit_obj, + JSON_COMPACT))); + json_decref (deposit_obj); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "URL for deposit: `%s'\n", + dh->url); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + dh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + dh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (dh->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &dh->db)); + ctx = MAH_handle_to_context (exchange); + dh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_deposit_finished, + dh); + return dh; +} + + +/** + * Cancel a deposit permission request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param deposit the deposit permission request handle + */ +void +TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit) +{ + if (NULL != deposit->job) + { + MAC_job_cancel (deposit->job); + deposit->job = NULL; + } + GNUNET_free_non_null (deposit->db.buf); + GNUNET_free (deposit->url); + GNUNET_free (deposit->json_enc); + GNUNET_free (deposit); +} + + +/* end of exchange_api_deposit.c */ diff --git a/src/exchange-lib/exchange_api_deposit_wtid.c b/src/exchange-lib/exchange_api_deposit_wtid.c new file mode 100644 index 000000000..83beb03ae --- /dev/null +++ b/src/exchange-lib/exchange_api_deposit_wtid.c @@ -0,0 +1,379 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_deposit_wtid.c + * @brief Implementation of the /deposit/wtid request of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief A Deposit Wtid Handle + */ +struct TALER_EXCHANGE_DepositWtidHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_DepositWtidCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Information the exchange should sign in response. + * (with pre-filled fields from the request). + */ + struct TALER_ConfirmWirePS depconf; + +}; + + +/** + * Verify that the signature on the "200 OK" response + * from the exchange is valid. + * + * @param dwh deposit wtid handle + * @param json json reply with the signature + * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not + */ +static int +verify_deposit_wtid_signature_ok (const struct TALER_EXCHANGE_DepositWtidHandle *dwh, + json_t *json) +{ + struct TALER_ExchangeSignatureP exchange_sig; + struct TALER_ExchangePublicKeyP exchange_pub; + const struct TALER_EXCHANGE_Keys *key_state; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("exchange_sig", &exchange_sig), + MAJ_spec_fixed_auto ("exchange_pub", &exchange_pub), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + key_state = TALER_EXCHANGE_get_keys (dwh->exchange); + if (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_state, + &exchange_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE, + &dwh->depconf.purpose, + &exchange_sig.eddsa_signature, + &exchange_pub.eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /deposit/wtid request. + * + * @param cls the `struct TALER_EXCHANGE_DepositWtidHandle` + * @param eh the curl request handle + */ +static void +handle_deposit_wtid_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_DepositWtidHandle *dwh = cls; + long response_code; + json_t *json; + const struct TALER_WireTransferIdentifierRawP *wtid = NULL; + struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS; + const struct TALER_Amount *coin_contribution = NULL; + struct TALER_Amount coin_contribution_s; + + dwh->job = NULL; + json = MAC_download_get_result (&dwh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid), + MAJ_spec_absolute_time ("execution_time", &execution_time), + MAJ_spec_amount ("coin_contribution", &coin_contribution_s), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + wtid = &dwh->depconf.wtid; + dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time); + TALER_amount_hton (&dwh->depconf.coin_contribution, + &coin_contribution_s); + coin_contribution = &coin_contribution_s; + if (GNUNET_OK != + verify_deposit_wtid_signature_ok (dwh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + } + break; + case MHD_HTTP_ACCEPTED: + { + /* Transaction known, but not executed yet */ + struct MAJ_Specification spec[] = { + MAJ_spec_absolute_time ("execution_time", &execution_time), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Exchange does not know about transaction; + we should pass the reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + dwh->cb (dwh->cb_cls, + response_code, + json, + wtid, + execution_time, + coin_contribution); + json_decref (json); + TALER_EXCHANGE_deposit_wtid_cancel (dwh); +} + + +/** + * Obtain wire transfer details about an existing deposit operation. + * + * @param exchange the exchange to query + * @param merchant_priv the merchant's private key + * @param h_wire hash of merchant's wire transfer details + * @param h_contract hash of the contract + * @param coin_pub public key of the coin + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure for @a cb + * @return handle to abort request + */ +struct TALER_EXCHANGE_DepositWtidHandle * +TALER_EXCHANGE_deposit_wtid (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_MerchantPrivateKeyP *merchant_priv, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + uint64_t transaction_id, + TALER_EXCHANGE_DepositWtidCallback cb, + void *cb_cls) +{ + struct TALER_DepositTrackPS dtp; + struct TALER_MerchantSignatureP merchant_sig; + struct TALER_EXCHANGE_DepositWtidHandle *dwh; + struct TALER_EXCHANGE_Context *ctx; + json_t *deposit_wtid_obj; + CURL *eh; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID); + dtp.purpose.size = htonl (sizeof (dtp)); + dtp.h_contract = *h_contract; + dtp.h_wire = *h_wire; + dtp.transaction_id = GNUNET_htonll (transaction_id); + GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv, + &dtp.merchant.eddsa_pub); + + dtp.coin_pub = *coin_pub; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, + &dtp.purpose, + &merchant_sig.eddsa_sig)); + deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */ + " s:o, s:I," /* coin_pub, transaction_id */ + " s:o, s:o}", /* merchant_pub, merchant_sig */ + "H_wire", TALER_json_from_data (h_wire, + sizeof (struct GNUNET_HashCode)), + "H_contract", TALER_json_from_data (h_contract, + sizeof (struct GNUNET_HashCode)), + "coin_pub", TALER_json_from_data (coin_pub, + sizeof (*coin_pub)), + "transaction_id", (json_int_t) transaction_id, + "merchant_pub", TALER_json_from_data (&dtp.merchant, + sizeof (struct TALER_MerchantPublicKeyP)), + "merchant_sig", TALER_json_from_data (&merchant_sig, + sizeof (merchant_sig))); + + dwh = GNUNET_new (struct TALER_EXCHANGE_DepositWtidHandle); + dwh->exchange = exchange; + dwh->cb = cb; + dwh->cb_cls = cb_cls; + dwh->url = MAH_path_to_url (exchange, "/deposit/wtid"); + dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); + dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE); + dwh->depconf.h_wire = *h_wire; + dwh->depconf.h_contract = *h_contract; + dwh->depconf.coin_pub = *coin_pub; + dwh->depconf.transaction_id = GNUNET_htonll (transaction_id); + + eh = curl_easy_init (); + GNUNET_assert (NULL != (dwh->json_enc = + json_dumps (deposit_wtid_obj, + JSON_COMPACT))); + json_decref (deposit_wtid_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + dwh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + dwh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (dwh->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &dwh->db)); + ctx = MAH_handle_to_context (exchange); + dwh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_deposit_wtid_finished, + dwh); + return dwh; +} + + +/** + * Cancel deposit wtid request. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param dwh the wire deposits request handle + */ +void +TALER_EXCHANGE_deposit_wtid_cancel (struct TALER_EXCHANGE_DepositWtidHandle *dwh) +{ + if (NULL != dwh->job) + { + MAC_job_cancel (dwh->job); + dwh->job = NULL; + } + GNUNET_free_non_null (dwh->db.buf); + GNUNET_free (dwh->url); + GNUNET_free (dwh->json_enc); + GNUNET_free (dwh); +} + + +/* end of exchange_api_deposit_wtid.c */ diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c new file mode 100644 index 000000000..d4b3e4deb --- /dev/null +++ b/src/exchange-lib/exchange_api_handle.c @@ -0,0 +1,902 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_handle.c + * @brief Implementation of the "handle" component of the exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler_exchange_service.h" +#include "taler_signatures.h" +#include "exchange_api_context.h" +#include "exchange_api_json.h" +#include "exchange_api_handle.h" + + +/** + * Log error related to CURL operations. + * + * @param type log level + * @param function which function failed to run + * @param code what was the curl error code + */ +#define CURL_STRERROR(type, function, code) \ + GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ + function, __FILE__, __LINE__, curl_easy_strerror (code)); + + +/** + * Stages of initialization for the `struct TALER_EXCHANGE_Handle` + */ +enum ExchangeHandleState +{ + /** + * Just allocated. + */ + MHS_INIT = 0, + + /** + * Obtained the exchange's certification data and keys. + */ + MHS_CERT = 1, + + /** + * Failed to initialize (fatal). + */ + MHS_FAILED = 2 +}; + + +/** + * Data for the request to get the /keys of a exchange. + */ +struct KeysRequest; + + +/** + * Handle to the exchange + */ +struct TALER_EXCHANGE_Handle +{ + /** + * The context of this handle + */ + struct TALER_EXCHANGE_Context *ctx; + + /** + * The URL of the exchange (i.e. "http://exchange.taler.net/") + */ + char *url; + + /** + * Function to call with the exchange's certification data, + * NULL if this has already been done. + */ + TALER_EXCHANGE_CertificationCallback cert_cb; + + /** + * Closure to pass to @e cert_cb. + */ + void *cert_cb_cls; + + /** + * Data for the request to get the /keys of a exchange, + * NULL once we are past stage #MHS_INIT. + */ + struct KeysRequest *kr; + + /** + * Key data of the exchange, only valid if + * @e handshake_complete is past stage #MHS_CERT. + */ + struct TALER_EXCHANGE_Keys key_data; + + /** + * Stage of the exchange's initialization routines. + */ + enum ExchangeHandleState state; + +}; + + +/* ***************** Internal /keys fetching ************* */ + +/** + * Data for the request to get the /keys of a exchange. + */ +struct KeysRequest +{ + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this handle + */ + char *url; + + /** + * Entry for this request with the `struct TALER_EXCHANGE_Context`. + */ + struct MAC_Job *job; + + /** + * Data structure for the download. + */ + struct MAC_DownloadBuffer db; + +}; + + +/** + * Release memory occupied by a keys request. + * Note that this does not cancel the request + * itself. + * + * @param kr request to free + */ +static void +free_keys_request (struct KeysRequest *kr) +{ + GNUNET_free_non_null (kr->db.buf); + GNUNET_free (kr->url); + GNUNET_free (kr); +} + + +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Parse a exchange's signing key encoded in JSON. + * + * @param[out] sign_key where to return the result + * @param[in] sign_key_obj json to parse + * @param master_key master key to use to verify signature + * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is + * invalid or the json malformed. + */ +static int +parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, + json_t *sign_key_obj, + const struct TALER_MasterPublicKeyP *master_key) +{ + struct TALER_ExchangeSigningKeyValidityPS sign_key_issue; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct GNUNET_TIME_Absolute valid_from; + struct GNUNET_TIME_Absolute valid_until; + struct GNUNET_TIME_Absolute valid_legal; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("master_sig", + &sig), + MAJ_spec_fixed_auto ("key", + &sign_key_issue.signkey_pub), + MAJ_spec_absolute_time ("stamp_start", + &valid_from), + MAJ_spec_absolute_time ("stamp_expire", + &valid_until), + MAJ_spec_absolute_time ("stamp_end", + &valid_legal), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (sign_key_obj, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); + sign_key_issue.purpose.size = + htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS) + - offsetof (struct TALER_ExchangeSigningKeyValidityPS, + purpose)); + sign_key_issue.master_public_key = *master_key; + sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); + sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until); + sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, + &sign_key_issue.purpose, + &sig, + &master_key->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + sign_key->valid_from = valid_from; + sign_key->valid_until = valid_until; + sign_key->key = sign_key_issue.signkey_pub; + return GNUNET_OK; +} + + +/** + * Parse a exchange's denomination key encoded in JSON. + * + * @param[out] denom_key where to return the result + * @param[in] denom_key_obj json to parse + * @param master_key master key to use to verify signature + * @param hash_context where to accumulate data for signature verification + * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is + * invalid or the json malformed. + */ +static int +parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, + json_t *denom_key_obj, + struct TALER_MasterPublicKeyP *master_key, + struct GNUNET_HashContext *hash_context) +{ + struct GNUNET_TIME_Absolute valid_from; + struct GNUNET_TIME_Absolute withdraw_valid_until; + struct GNUNET_TIME_Absolute deposit_valid_until; + struct GNUNET_TIME_Absolute expire_legal; + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + struct TALER_Amount fee_deposit; + struct TALER_Amount fee_refresh; + struct TALER_DenominationKeyValidityPS denom_key_issue; + struct GNUNET_CRYPTO_rsa_PublicKey *pk; + struct GNUNET_CRYPTO_EddsaSignature sig; + + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("master_sig", + &sig), + MAJ_spec_absolute_time ("stamp_expire_deposit", + &deposit_valid_until), + MAJ_spec_absolute_time ("stamp_expire_withdraw", + &withdraw_valid_until), + MAJ_spec_absolute_time ("stamp_start", + &valid_from), + MAJ_spec_absolute_time ("stamp_expire_legal", + &expire_legal), + MAJ_spec_amount ("value", + &value), + MAJ_spec_amount ("fee_withdraw", + &fee_withdraw), + MAJ_spec_amount ("fee_deposit", + &fee_deposit), + MAJ_spec_amount ("fee_refresh", + &fee_refresh), + MAJ_spec_rsa_public_key ("denom_pub", + &pk), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (denom_key_obj, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + memset (&denom_key_issue, 0, sizeof (denom_key_issue)); + GNUNET_CRYPTO_rsa_public_key_hash (pk, + &denom_key_issue.denom_hash); + denom_key_issue.purpose.purpose + = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); + denom_key_issue.purpose.size + = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); + denom_key_issue.master = *master_key; + denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); + denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until); + denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until); + denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal); + TALER_amount_hton (&denom_key_issue.value, + &value); + TALER_amount_hton (&denom_key_issue.fee_withdraw, + &fee_withdraw); + TALER_amount_hton (&denom_key_issue.fee_deposit, + &fee_deposit); + TALER_amount_hton (&denom_key_issue.fee_refresh, + &fee_refresh); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, + &denom_key_issue.purpose, + &sig, + &master_key->eddsa_pub)); + GNUNET_CRYPTO_hash_context_read (hash_context, + &denom_key_issue.denom_hash, + sizeof (struct GNUNET_HashCode)); + denom_key->key.rsa_public_key = pk; + denom_key->h_key = denom_key_issue.denom_hash; + denom_key->valid_from = valid_from; + denom_key->withdraw_valid_until = withdraw_valid_until; + denom_key->deposit_valid_until = deposit_valid_until; + denom_key->expire_legal = expire_legal; + denom_key->value = value; + denom_key->fee_withdraw = fee_withdraw; + denom_key->fee_deposit = fee_deposit; + denom_key->fee_refresh = fee_refresh; + return GNUNET_OK; + + EXITIF_exit: + MAJ_parse_free (spec); + return GNUNET_SYSERR; +} + + +/** + * Parse a exchange's auditor information encoded in JSON. + * + * @param[out] auditor where to return the result + * @param[in] auditor_obj json to parse + * @param key_data information about denomination keys + * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is + * invalid or the json malformed. + */ +static int +parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, + json_t *auditor_obj, + const struct TALER_EXCHANGE_Keys *key_data) +{ + json_t *keys; + json_t *key; + unsigned int len; + unsigned int off; + unsigned int i; + struct TALER_ExchangeKeyValidityPS kv; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("auditor_pub", + &auditor->auditor_pub), + MAJ_spec_json ("denomination_keys", + &keys), + MAJ_spec_end + }; + + auditor->auditor_url = NULL; /* #3987 */ + if (GNUNET_OK != + MAJ_parse_json (auditor_obj, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); + kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); + kv.master = key_data->master_pub; + len = json_array_size (keys); + auditor->denom_keys = GNUNET_new_array (len, + const struct TALER_EXCHANGE_DenomPublicKey *); + i = 0; + off = 0; + json_array_foreach (keys, i, key) { + struct TALER_AuditorSignatureP auditor_sig; + struct GNUNET_HashCode denom_h; + const struct TALER_EXCHANGE_DenomPublicKey *dk; + unsigned int j; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("denom_pub_h", + &denom_h), + MAJ_spec_fixed_auto ("auditor_sig", + &auditor_sig), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (key, + spec)) + { + GNUNET_break_op (0); + continue; + } + dk = NULL; + for (j=0;j<key_data->num_denom_keys;j++) + { + if (0 == memcmp (&denom_h, + &key_data->denom_keys[j].h_key, + sizeof (struct GNUNET_HashCode))) + { + dk = &key_data->denom_keys[j]; + break; + } + } + if (NULL == dk) + { + GNUNET_break_op (0); + continue; + } + kv.start = GNUNET_TIME_absolute_hton (dk->valid_from); + kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until); + kv.expire_spend = GNUNET_TIME_absolute_hton (dk->deposit_valid_until); + kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal); + TALER_amount_hton (&kv.value, + &dk->value); + TALER_amount_hton (&kv.fee_withdraw, + &dk->fee_withdraw); + TALER_amount_hton (&kv.fee_deposit, + &dk->fee_deposit); + TALER_amount_hton (&kv.fee_refresh, + &dk->fee_refresh); + kv.denom_hash = dk->h_key; + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS, + &kv.purpose, + &auditor_sig.eddsa_sig, + &auditor->auditor_pub.eddsa_pub)) + { + GNUNET_break_op (0); + continue; + } + auditor->denom_keys[off] = dk; + off++; + } + auditor->num_denom_keys = off; + return GNUNET_OK; +} + + +/** + * Decode the JSON in @a resp_obj from the /keys response and store the data + * in the @a key_data. + * + * @param[in] resp_obj JSON object to parse + * @param[out] key_data where to store the results we decoded + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON) + */ +static int +decode_keys_json (json_t *resp_obj, + struct TALER_EXCHANGE_Keys *key_data) +{ + struct GNUNET_TIME_Absolute list_issue_date; + struct TALER_ExchangeSignatureP sig; + struct TALER_ExchangeKeySetPS ks; + struct GNUNET_HashContext *hash_context; + struct TALER_ExchangePublicKeyP pub; + + if (JSON_OBJECT != json_typeof (resp_obj)) + return GNUNET_SYSERR; + + hash_context = GNUNET_CRYPTO_hash_context_start (); + /* parse the master public key and issue date of the response */ + { + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("master_public_key", + &key_data->master_pub), + MAJ_spec_fixed_auto ("eddsa_sig", + &sig), + MAJ_spec_fixed_auto ("eddsa_pub", + &pub), + MAJ_spec_absolute_time ("list_issue_date", + &list_issue_date), + MAJ_spec_end + }; + + EXITIF (GNUNET_OK != + MAJ_parse_json (resp_obj, + spec)); + } + + /* parse the signing keys */ + { + json_t *sign_keys_array; + json_t *sign_key_obj; + unsigned int index; + + EXITIF (NULL == (sign_keys_array = + json_object_get (resp_obj, + "signkeys"))); + EXITIF (JSON_ARRAY != json_typeof (sign_keys_array)); + EXITIF (0 == (key_data->num_sign_keys = + json_array_size (sign_keys_array))); + key_data->sign_keys + = GNUNET_new_array (key_data->num_sign_keys, + struct TALER_EXCHANGE_SigningPublicKey); + index = 0; + json_array_foreach (sign_keys_array, index, sign_key_obj) { + EXITIF (GNUNET_SYSERR == + parse_json_signkey (&key_data->sign_keys[index], + sign_key_obj, + &key_data->master_pub)); + } + } + + /* parse the denomination keys */ + { + json_t *denom_keys_array; + json_t *denom_key_obj; + unsigned int index; + + EXITIF (NULL == (denom_keys_array = + json_object_get (resp_obj, "denoms"))); + EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); + EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array))); + key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys, + struct TALER_EXCHANGE_DenomPublicKey); + index = 0; + json_array_foreach (denom_keys_array, index, denom_key_obj) { + EXITIF (GNUNET_SYSERR == + parse_json_denomkey (&key_data->denom_keys[index], + denom_key_obj, + &key_data->master_pub, + hash_context)); + } + } + + /* parse the auditor information */ + { + json_t *auditors_array; + json_t *auditor_info; + unsigned int len; + unsigned int index; + + EXITIF (NULL == (auditors_array = + json_object_get (resp_obj, "auditors"))); + EXITIF (JSON_ARRAY != json_typeof (auditors_array)); + len = json_array_size (auditors_array); + if (0 != len) + { + key_data->auditors = GNUNET_new_array (len, + struct TALER_EXCHANGE_AuditorInformation); + index = 0; + json_array_foreach (auditors_array, index, auditor_info) { + EXITIF (GNUNET_SYSERR == + parse_json_auditor (&key_data->auditors[index], + auditor_info, + key_data)); + } + } + } + + /* Validate signature... */ + ks.purpose.size = htonl (sizeof (ks)); + ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET); + ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date); + GNUNET_CRYPTO_hash_context_finish (hash_context, + &ks.hc); + hash_context = NULL; + EXITIF (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_data, + &pub)); + EXITIF (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET, + &ks.purpose, + &sig.eddsa_signature, + &pub.eddsa_pub)); + return GNUNET_OK; + EXITIF_exit: + + if (NULL != hash_context) + GNUNET_CRYPTO_hash_context_abort (hash_context); + return GNUNET_SYSERR; +} + + +/** + * Callback used when downloading the reply to a /keys request + * is complete. + * + * @param cls the `struct KeysRequest` + * @param eh easy handle of the original request + */ +static void +keys_completed_cb (void *cls, + CURL *eh) +{ + struct KeysRequest *kr = cls; + struct TALER_EXCHANGE_Handle *exchange = kr->exchange; + json_t *resp_obj; + long response_code; + TALER_EXCHANGE_CertificationCallback cb; + + resp_obj = MAC_download_get_result (&kr->db, + eh, + &response_code); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received keys from URL `%s' with status %ld.\n", + kr->url, + response_code); + switch (response_code) { + case 0: + break; + case MHD_HTTP_OK: + if ( (NULL == resp_obj) || + (GNUNET_OK != + decode_keys_json (resp_obj, + &kr->exchange->key_data)) ) + response_code = 0; + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + break; + } + if (NULL != resp_obj) + json_decref (resp_obj); + + if (MHD_HTTP_OK != response_code) + { + exchange->kr = NULL; + free_keys_request (kr); + exchange->state = MHS_FAILED; + /* notify application that we failed */ + if (NULL != (cb = exchange->cert_cb)) + { + exchange->cert_cb = NULL; + cb (exchange->cert_cb_cls, + NULL); + } + return; + } + exchange->kr = NULL; + free_keys_request (kr); + exchange->state = MHS_CERT; + /* notify application about the key information */ + if (NULL != (cb = exchange->cert_cb)) + { + exchange->cert_cb = NULL; + cb (exchange->cert_cb_cls, + &exchange->key_data); + } +} + + +/* ********************* library internal API ********* */ + + +/** + * Get the context of a exchange. + * + * @param h the exchange handle to query + * @return ctx context to execute jobs in + */ +struct TALER_EXCHANGE_Context * +MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h) +{ + return h->ctx; +} + + +/** + * Check if the handle is ready to process requests. + * + * @param h the exchange handle to query + * @return #GNUNET_YES if we are ready, #GNUNET_NO if not + */ +int +MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h) +{ + return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Obtain the URL to use for an API request. + * + * @param h the exchange handle to query + * @param path Taler API path (i.e. "/reserve/withdraw") + * @return the full URI to use with cURL + */ +char * +MAH_path_to_url (struct TALER_EXCHANGE_Handle *h, + const char *path) +{ + char *url; + + if ( ('/' == path[0]) && + (0 < strlen (h->url)) && + ('/' == h->url[strlen (h->url) - 1]) ) + path++; /* avoid generating URL with "//" from concat */ + GNUNET_asprintf (&url, + "%s%s", + h->url, + path); + return url; +} + + +/* ********************* public API ******************* */ + +/** + * Initialise a connection to the exchange. Will connect to the + * exchange and obtain information about the exchange's master public + * key and the exchange's auditor. The respective information will + * be passed to the @a cert_cb once available, and all future + * interactions with the exchange will be checked to be signed + * (where appropriate) by the respective master key. + * + * @param ctx the context + * @param url HTTP base URL for the exchange + * @param cert_cb function to call with the exchange's certification information + * @param cert_cb_cls closure for @a cert_cb + * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END. + * @return the exchange handle; NULL upon error + */ +struct TALER_EXCHANGE_Handle * +TALER_EXCHANGE_connect (struct TALER_EXCHANGE_Context *ctx, + const char *url, + TALER_EXCHANGE_CertificationCallback cert_cb, + void *cert_cb_cls, + ...) +{ + struct TALER_EXCHANGE_Handle *exchange; + struct KeysRequest *kr; + CURL *c; + + exchange = GNUNET_new (struct TALER_EXCHANGE_Handle); + exchange->ctx = ctx; + exchange->url = GNUNET_strdup (url); + exchange->cert_cb = cert_cb; + exchange->cert_cb_cls = cert_cb_cls; + kr = GNUNET_new (struct KeysRequest); + kr->exchange = exchange; + kr->url = MAH_path_to_url (exchange, "/keys"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting keys with URL `%s'.\n", + kr->url); + c = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (c, + CURLOPT_VERBOSE, + 0)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (c, + CURLOPT_STDERR, + stdout)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (c, + CURLOPT_URL, + kr->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (c, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (c, + CURLOPT_WRITEDATA, + &kr->db)); + kr->job = MAC_job_add (exchange->ctx, + c, + GNUNET_NO, + &keys_completed_cb, + kr); + exchange->kr = kr; + return exchange; +} + + +/** + * Disconnect from the exchange + * + * @param exchange the exchange handle + */ +void +TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) +{ + unsigned int i; + + if (NULL != exchange->kr) + { + MAC_job_cancel (exchange->kr->job); + free_keys_request (exchange->kr); + exchange->kr = NULL; + } + GNUNET_array_grow (exchange->key_data.sign_keys, + exchange->key_data.num_sign_keys, + 0); + for (i=0;i<exchange->key_data.num_denom_keys;i++) + GNUNET_CRYPTO_rsa_public_key_free (exchange->key_data.denom_keys[i].key.rsa_public_key); + GNUNET_array_grow (exchange->key_data.denom_keys, + exchange->key_data.num_denom_keys, + 0); + GNUNET_array_grow (exchange->key_data.auditors, + exchange->key_data.num_auditors, + 0); + GNUNET_free (exchange->url); + GNUNET_free (exchange); +} + + +/** + * Test if the given @a pub is a the current signing key from the exchange + * according to @a keys. + * + * @param keys the exchange's key set + * @param pub claimed current online signing key for the exchange + * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key + */ +int +TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_ExchangePublicKeyP *pub) +{ + struct GNUNET_TIME_Absolute now; + unsigned int i; + + /* we will check using a tolerance of 1h for the time */ + now = GNUNET_TIME_absolute_get (); + for (i=0;i<keys->num_sign_keys;i++) + if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) && + (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) && + (0 == memcmp (pub, + &keys->sign_keys[i].key, + sizeof (struct TALER_ExchangePublicKeyP))) ) + return GNUNET_OK; + return GNUNET_SYSERR; +} + + +/** + * Obtain the denomination key details from the exchange. + * + * @param keys the exchange's key set + * @param pk public key of the denomination to lookup + * @return details about the given denomination key, NULL if the key is + * not found + */ +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_DenominationPublicKey *pk) +{ + unsigned int i; + + for (i=0;i<keys->num_denom_keys;i++) + if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key, + keys->denom_keys[i].key.rsa_public_key)) + return &keys->denom_keys[i]; + return NULL; +} + + +/** + * Obtain the denomination key details from the exchange. + * + * @param keys the exchange's key set + * @param hc hash of the public key of the denomination to lookup + * @return details about the given denomination key + */ +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys, + const struct GNUNET_HashCode *hc) +{ + unsigned int i; + + for (i=0;i<keys->num_denom_keys;i++) + if (0 == memcmp (hc, + &keys->denom_keys[i].h_key, + sizeof (struct GNUNET_HashCode))) + return &keys->denom_keys[i]; + return NULL; +} + + +/** + * Obtain the keys from the exchange. + * + * @param exchange the exchange handle + * @return the exchange's key set + */ +const struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange) +{ + return &exchange->key_data; +} + + +/* end of exchange_api_handle.c */ diff --git a/src/exchange-lib/exchange_api_handle.h b/src/exchange-lib/exchange_api_handle.h new file mode 100644 index 000000000..48423a7b8 --- /dev/null +++ b/src/exchange-lib/exchange_api_handle.h @@ -0,0 +1,59 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_handle.h + * @brief Internal interface to the handle part of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include "taler_exchange_service.h" + + +/** + * Get the context of a exchange. + * + * @param h the exchange handle to query + * @return ctx context to execute jobs in + */ +struct TALER_EXCHANGE_Context * +MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h); + + +/** + * Check if the handle is ready to process requests. + * + * @param h the exchange handle to query + * @return #GNUNET_YES if we are ready, #GNUNET_NO if not + */ +int +MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h); + + +/** + * Obtain the URL to use for an API request. + * + * @param h the exchange handle to query + * @param path Taler API path (i.e. "/reserve/withdraw") + * @return the full URI to use with cURL + */ +char * +MAH_path_to_url (struct TALER_EXCHANGE_Handle *h, + const char *path); + + +/* end of exchange_api_handle.h */ diff --git a/src/exchange-lib/exchange_api_json.c b/src/exchange-lib/exchange_api_json.c new file mode 100644 index 000000000..d91feba0e --- /dev/null +++ b/src/exchange-lib/exchange_api_json.c @@ -0,0 +1,525 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_json.c + * @brief functions to parse incoming requests (JSON snippets) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include "exchange_api_json.h" + +/** + * Navigate and parse data in a JSON tree. + * + * @param root the JSON node to start the navigation at. + * @param spec parse specification array + * @return offset in @a spec where parsing failed, -1 on success (!) + */ +static int +parse_json (json_t *root, + struct MAJ_Specification *spec) +{ + int i; + json_t *pos; /* what's our current position? */ + + pos = root; + for (i=0;MAJ_CMD_END != spec[i].cmd;i++) + { + pos = json_object_get (root, + spec[i].field); + if (NULL == pos) + { + GNUNET_break_op (0); + return i; + } + switch (spec[i].cmd) + { + case MAJ_CMD_END: + GNUNET_assert (0); + return i; + case MAJ_CMD_AMOUNT: + if (GNUNET_OK != + TALER_json_to_amount (pos, + spec[i].details.amount)) + { + GNUNET_break_op (0); + return i; + } + break; + case MAJ_CMD_TIME_ABSOLUTE: + if (GNUNET_OK != + TALER_json_to_abs (pos, + spec[i].details.abs_time)) + { + GNUNET_break_op (0); + return i; + } + break; + + case MAJ_CMD_STRING: + { + const char *str; + + str = json_string_value (pos); + if (NULL == str) + { + GNUNET_break_op (0); + return i; + } + *spec[i].details.strptr = str; + } + break; + + case MAJ_CMD_BINARY_FIXED: + { + const char *str; + int res; + + str = json_string_value (pos); + if (NULL == str) + { + GNUNET_break_op (0); + return i; + } + res = GNUNET_STRINGS_string_to_data (str, strlen (str), + spec[i].details.fixed_data.dest, + spec[i].details.fixed_data.dest_size); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + return i; + } + } + break; + + case MAJ_CMD_BINARY_VARIABLE: + { + const char *str; + size_t size; + void *data; + int res; + + str = json_string_value (pos); + if (NULL == str) + { + GNUNET_break_op (0); + return i; + } + size = (strlen (str) * 5) / 8; + if (size >= 1024) + { + GNUNET_break_op (0); + return i; + } + data = GNUNET_malloc (size); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + data, + size); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + GNUNET_free (data); + return i; + } + *spec[i].details.variable_data.dest_p = data; + *spec[i].details.variable_data.dest_size_p = size; + } + break; + + case MAJ_CMD_RSA_PUBLIC_KEY: + { + size_t size; + const char *str; + int res; + void *buf; + + str = json_string_value (pos); + if (NULL == str) + { + GNUNET_break_op (0); + return i; + } + size = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (size); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + size); + if (GNUNET_OK != res) + { + GNUNET_free (buf); + GNUNET_break_op (0); + return i; + } + *spec[i].details.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_decode (buf, + size); + GNUNET_free (buf); + if (NULL == spec[i].details.rsa_public_key) + { + GNUNET_break_op (0); + return i; + } + } + break; + + case MAJ_CMD_RSA_SIGNATURE: + { + size_t size; + const char *str; + int res; + void *buf; + + str = json_string_value (pos); + if (NULL == str) + { + GNUNET_break_op (0); + return i; + } + size = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (size); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + size); + if (GNUNET_OK != res) + { + GNUNET_free (buf); + GNUNET_break_op (0); + return i; + } + *spec[i].details.rsa_signature + = GNUNET_CRYPTO_rsa_signature_decode (buf, + size); + GNUNET_free (buf); + if (NULL == spec[i].details.rsa_signature) + return i; + } + break; + + case MAJ_CMD_UINT16: + { + json_int_t val; + + if (! json_is_integer (pos)) + { + GNUNET_break_op (0); + return i; + } + val = json_integer_value (pos); + if ( (0 > val) || (val > UINT16_MAX) ) + { + GNUNET_break_op (0); + return i; + } + *spec[i].details.u16 = (uint16_t) val; + } + break; + + case MAJ_CMD_UINT64: + { + json_int_t val; + + if (! json_is_integer (pos)) + { + GNUNET_break_op (0); + return i; + } + val = json_integer_value (pos); + *spec[i].details.u64 = (uint64_t) val; + } + break; + + case MAJ_CMD_JSON_OBJECT: + { + if (! (json_is_object (pos) || json_is_array (pos)) ) + { + GNUNET_break_op (0); + return i; + } + json_incref (pos); + *spec[i].details.obj = pos; + } + break; + + default: + GNUNET_break (0); + return i; + } + } + return -1; /* all OK! */ +} + + +/** + * Free all elements allocated during a + * #MAJ_parse_json() operation. + * + * @param spec specification of the parse operation + * @param end number of elements in @a spec to process + */ +static void +parse_free (struct MAJ_Specification *spec, + int end) +{ + int i; + + for (i=0;i<end;i++) + { + switch (spec[i].cmd) + { + case MAJ_CMD_END: + GNUNET_assert (0); + return; + case MAJ_CMD_AMOUNT: + break; + case MAJ_CMD_TIME_ABSOLUTE: + break; + case MAJ_CMD_BINARY_FIXED: + break; + case MAJ_CMD_STRING: + break; + case MAJ_CMD_BINARY_VARIABLE: + GNUNET_free (*spec[i].details.variable_data.dest_p); + *spec[i].details.variable_data.dest_p = NULL; + *spec[i].details.variable_data.dest_size_p = 0; + break; + case MAJ_CMD_RSA_PUBLIC_KEY: + GNUNET_CRYPTO_rsa_public_key_free (*spec[i].details.rsa_public_key); + *spec[i].details.rsa_public_key = NULL; + break; + case MAJ_CMD_RSA_SIGNATURE: + GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature); + *spec[i].details.rsa_signature = NULL; + break; + case MAJ_CMD_JSON_OBJECT: + json_decref (*spec[i].details.obj); + *spec[i].details.obj = NULL; + break; + default: + GNUNET_break (0); + break; + } + } +} + + +/** + * Navigate and parse data in a JSON tree. + * + * @param root the JSON node to start the navigation at. + * @param spec parse specification array + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +MAJ_parse_json (const json_t *root, + struct MAJ_Specification *spec) +{ + int ret; + + ret = parse_json ((json_t *) root, + spec); + if (-1 == ret) + return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "JSON field `%s` (%d) had unexpected value\n", + spec[ret].field, + ret); + parse_free (spec, ret); + return GNUNET_SYSERR; +} + + +/** + * Free all elements allocated during a + * #MAJ_parse_json() operation. + * + * @param spec specification of the parse operation + */ +void +MAJ_parse_free (struct MAJ_Specification *spec) +{ + int i; + + for (i=0;MAJ_CMD_END != spec[i].cmd;i++) ; + parse_free (spec, i); +} + + +/** + * The expected field stores a string. + * + * @param name name of the JSON field + * @param strptr where to store a pointer to the field + */ +struct MAJ_Specification +MAJ_spec_string (const char *name, + const char **strptr) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_STRING, + .field = name, + .details.strptr = strptr + }; + return ret; +} + + +/** + * Specification for parsing an absolute time value. + * + * @param name name of the JSON field + * @param at where to store the absolute time found under @a name + */ +struct MAJ_Specification +MAJ_spec_absolute_time (const char *name, + struct GNUNET_TIME_Absolute *at) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_TIME_ABSOLUTE, + .field = name, + .details.abs_time = at + }; + return ret; +} + + +/** + * Specification for parsing an amount value. + * + * @param name name of the JSON field + * @param amount where to store the amount found under @a name + */ +struct MAJ_Specification +MAJ_spec_amount (const char *name, + struct TALER_Amount *amount) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_AMOUNT, + .field = name, + .details.amount = amount + }; + return ret; +} + + +/** + * 16-bit integer. + * + * @param name name of the JSON field + * @param[out] u16 where to store the integer found under @a name + */ +struct MAJ_Specification +MAJ_spec_uint16 (const char *name, + uint16_t *u16) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_UINT16, + .field = name, + .details.u16 = u16 + }; + return ret; +} + + +/** + * 64-bit integer. + * + * @param name name of the JSON field + * @param[out] u64 where to store the integer found under @a name + */ +struct MAJ_Specification +MAJ_spec_uint64 (const char *name, + uint64_t *u64) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_UINT64, + .field = name, + .details.u64 = u64 + }; + return ret; +} + + +/** + * JSON object. + * + * @param name name of the JSON field + * @param[out] jsonp where to store the JSON found under @a name + */ +struct MAJ_Specification +MAJ_spec_json (const char *name, + json_t **jsonp) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_JSON_OBJECT, + .field = name, + .details.obj = jsonp + }; + return ret; +} + + +/** + * Specification for parsing an RSA public key. + * + * @param name name of the JSON field + * @param pk where to store the RSA key found under @a name + */ +struct MAJ_Specification +MAJ_spec_rsa_public_key (const char *name, + struct GNUNET_CRYPTO_rsa_PublicKey **pk) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_RSA_PUBLIC_KEY, + .field = name, + .details.rsa_public_key = pk + }; + return ret; +} + + +/** + * Specification for parsing an RSA signature. + * + * @param name name of the JSON field + * @param sig where to store the RSA signature found under @a name + */ +struct MAJ_Specification +MAJ_spec_rsa_signature (const char *name, + struct GNUNET_CRYPTO_rsa_Signature **sig) +{ + struct MAJ_Specification ret = + { + .cmd = MAJ_CMD_RSA_SIGNATURE, + .field = name, + .details.rsa_signature = sig + }; + return ret; +} + + +/* end of exchange_api_json.c */ diff --git a/src/exchange-lib/exchange_api_json.h b/src/exchange-lib/exchange_api_json.h new file mode 100644 index 000000000..41efcea68 --- /dev/null +++ b/src/exchange-lib/exchange_api_json.h @@ -0,0 +1,352 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_json.h + * @brief functions to parse incoming requests (JSON snippets) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler_util.h" +#include <jansson.h> + + +/** + * Enumeration with the various commands for the + * #MAJ_parse_json interpreter. + */ +enum MAJ_Command +{ + + /** + * End of command list. + */ + MAJ_CMD_END, + + /** + * Parse amount at current position. + */ + MAJ_CMD_AMOUNT, + + /** + * Parse absolute time at current position. + */ + MAJ_CMD_TIME_ABSOLUTE, + + /** + * Parse fixed binary value at current position. + */ + MAJ_CMD_BINARY_FIXED, + + /** + * Parse variable-size binary value at current position. + */ + MAJ_CMD_BINARY_VARIABLE, + + /** + * Parse RSA public key at current position. + */ + MAJ_CMD_RSA_PUBLIC_KEY, + + /** + * Parse RSA signature at current position. + */ + MAJ_CMD_RSA_SIGNATURE, + + /** + * Parse `const char *` JSON string at current position. + */ + MAJ_CMD_STRING, + + /** + * Parse `uint16_t` integer at the current position. + */ + MAJ_CMD_UINT16, + + /** + * Parse `uint64_t` integer at the current position. + */ + MAJ_CMD_UINT64, + + /** + * Parse JSON object at the current position. + */ + MAJ_CMD_JSON_OBJECT, + + /** + * Parse ??? at current position. + */ + MAJ_CMD_C + +}; + + +/** + * @brief Entry in parser specification for #MAJ_parse_json. + */ +struct MAJ_Specification +{ + + /** + * Command to execute. + */ + enum MAJ_Command cmd; + + /** + * Name of the field to access. + */ + const char *field; + + /** + * Further details for the command. + */ + union { + + /** + * Where to store amount for #MAJ_CMD_AMOUNT. + */ + struct TALER_Amount *amount; + + /** + * Where to store time, for #MAJ_CMD_TIME_ABSOLUTE. + */ + struct GNUNET_TIME_Absolute *abs_time; + + /** + * Where to write binary data, for #MAJ_CMD_BINARY_FIXED. + */ + struct { + /** + * Where to write the data. + */ + void *dest; + + /** + * How many bytes to write to @e dest. + */ + size_t dest_size; + + } fixed_data; + + /** + * Where to write binary data, for #MAJ_CMD_BINARY_VARIABLE. + */ + struct { + /** + * Where to store the pointer with the data (is allocated). + */ + void **dest_p; + + /** + * Where to store the number of bytes allocated at `*dest`. + */ + size_t *dest_size_p; + + } variable_data; + + /** + * Where to store the RSA public key for #MAJ_CMD_RSA_PUBLIC_KEY + */ + struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key; + + /** + * Where to store the RSA signature for #MAJ_CMD_RSA_SIGNATURE + */ + struct GNUNET_CRYPTO_rsa_Signature **rsa_signature; + + /** + * Details for #MAJ_CMD_EDDSA_SIGNATURE + */ + struct { + + /** + * Where to store the purpose. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose **purpose_p; + + /** + * Key to verify the signature against. + */ + const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key; + + } eddsa_signature; + + /** + * Where to store a pointer to the string. + */ + const char **strptr; + + /** + * Where to store 16-bit integer. + */ + uint16_t *u16; + + /** + * Where to store 64-bit integer. + */ + uint64_t *u64; + + /** + * Where to store a JSON object. + */ + json_t **obj; + + } details; + +}; + + +/** + * Navigate and parse data in a JSON tree. + * + * @param root the JSON node to start the navigation at. + * @param spec parse specification array + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +MAJ_parse_json (const json_t *root, + struct MAJ_Specification *spec); + + +/** + * Free all elements allocated during a + * #MAJ_parse_json() operation. + * + * @param spec specification of the parse operation + */ +void +MAJ_parse_free (struct MAJ_Specification *spec); + + +/** + * End of a parser specification. + */ +#define MAJ_spec_end { .cmd = MAJ_CMD_END } + +/** + * Fixed size object (in network byte order, encoded using Crockford + * Base32hex encoding). + * + * @param name name of the JSON field + * @param obj pointer where to write the data (type of `*obj` will determine size) + */ +#define MAJ_spec_fixed_auto(name,obj) { .cmd = MAJ_CMD_BINARY_FIXED, .field = name, .details.fixed_data.dest = obj, .details.fixed_data.dest_size = sizeof (*obj) } + + +/** + * Variable size object (in network byte order, encoded using Crockford + * Base32hex encoding). + * + * @param name name of the JSON field + * @param obj pointer where to write the data (a `void **`) + * @param size where to store the number of bytes allocated for @a obj (of type `size_t *` + */ +#define MAJ_spec_varsize(name,obj,size) { .cmd = MAJ_CMD_BINARY_VARIABLE, .field = name, .details.variable_data.dest_p = obj, .details.variable_data.dest_size_p = size } + + +/** + * The expected field stores a string. + * + * @param name name of the JSON field + * @param strptr where to store a pointer to the field + */ +struct MAJ_Specification +MAJ_spec_string (const char *name, + const char **strptr); + + +/** + * Absolute time. + * + * @param name name of the JSON field + * @param[out] at where to store the absolute time found under @a name + */ +struct MAJ_Specification +MAJ_spec_absolute_time (const char *name, + struct GNUNET_TIME_Absolute *at); + + +/** + * 16-bit integer. + * + * @param name name of the JSON field + * @param[out] u16 where to store the integer found under @a name + */ +struct MAJ_Specification +MAJ_spec_uint16 (const char *name, + uint16_t *u16); + + +/** + * 64-bit integer. + * + * @param name name of the JSON field + * @param[out] u64 where to store the integer found under @a name + */ +struct MAJ_Specification +MAJ_spec_uint64 (const char *name, + uint64_t *u64); + + +/** + * JSON object. + * + * @param name name of the JSON field + * @param[out] jsonp where to store the JSON found under @a name + */ +struct MAJ_Specification +MAJ_spec_json (const char *name, + json_t **jsonp); + + +/** + * Specification for parsing an amount value. + * + * @param name name of the JSON field + * @param amount where to store the amount under @a name + */ +struct MAJ_Specification +MAJ_spec_amount (const char *name, + struct TALER_Amount *amount); + + +/** + * Specification for parsing an RSA public key. + * + * @param name name of the JSON field + * @param pk where to store the RSA key found under @a name + */ +struct MAJ_Specification +MAJ_spec_rsa_public_key (const char *name, + struct GNUNET_CRYPTO_rsa_PublicKey **pk); + + +/** + * Specification for parsing an RSA signature. + * + * @param name name of the JSON field + * @param sig where to store the RSA signature found under @a name + */ +struct MAJ_Specification +MAJ_spec_rsa_signature (const char *name, + struct GNUNET_CRYPTO_rsa_Signature **sig); + + + + +/* end of exchange_api_json.h */ diff --git a/src/exchange-lib/exchange_api_refresh.c b/src/exchange-lib/exchange_api_refresh.c new file mode 100644 index 000000000..03d59ea3b --- /dev/null +++ b/src/exchange-lib/exchange_api_refresh.c @@ -0,0 +1,2061 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_refresh.c + * @brief Implementation of the /refresh/melt+reveal requests of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/* ********************* /refresh/ common ***************************** */ + +/* structures for committing refresh data to disk before doing the + network interaction(s) */ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header of serialized information about a coin we are melting. + */ +struct MeltedCoinP +{ + /** + * Private key of the coin. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * Amount this coin contributes to the melt, including fee. + */ + struct TALER_AmountNBO melt_amount_with_fee; + + /** + * The applicable fee for withdrawing a coin of this denomination + */ + struct TALER_AmountNBO fee_melt; + + /** + * The original value of the coin. + */ + struct TALER_AmountNBO original_value; + + /** + * Transfer private keys for each cut-and-choose dimension. + */ + struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA]; + + /** + * Timestamp indicating when coins of this denomination become invalid. + */ + struct GNUNET_TIME_AbsoluteNBO deposit_valid_until; + + /** + * Size of the encoded public key that follows. + */ + uint16_t pbuf_size; + + /** + * Size of the encoded signature that follows. + */ + uint16_t sbuf_size; + + /* Followed by serializations of: + 1) struct TALER_DenominationPublicKey pub_key; + 2) struct TALER_DenominationSignature sig; + */ +}; + + +/** + * Header for serializations of coin-specific information about the + * fresh coins we generate during a melt. + */ +struct FreshCoinP +{ + + /** + * Private key of the coin. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * Size of the encoded blinding key that follows. + */ + uint32_t bbuf_size; + + /* Followed by serialization of: + - struct TALER_DenominationBlindingKey blinding_key; + */ + +}; + + +/** + * Header of serialized data about a melt operation, suitable for + * persisting it on disk. + */ +struct MeltDataP +{ + + /** + * Hash over the melting session. + */ + struct GNUNET_HashCode melt_session_hash; + + /** + * Link secret used to encrypt the @a coin_priv and the blinding + * key in the linkage data for the respective cut-and-choose dimension. + */ + struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA]; + + /** + * Number of coins we are melting, in NBO + */ + uint16_t num_melted_coins GNUNET_PACKED; + + /** + * Number of coins we are creating, in NBO + */ + uint16_t num_fresh_coins GNUNET_PACKED; + + /* Followed by serializations of: + 1) struct MeltedCoinP melted_coins[num_melted_coins]; + 2) struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins]; + 3) TALER_CNC_KAPPA times: + 3a) struct FreshCoinP fresh_coins[num_fresh_coins]; + */ +}; + + +GNUNET_NETWORK_STRUCT_END + + +/** + * Information about a coin we are melting. + */ +struct MeltedCoin +{ + /** + * Private key of the coin. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * Amount this coin contributes to the melt, including fee. + */ + struct TALER_Amount melt_amount_with_fee; + + /** + * The applicable fee for melting a coin of this denomination + */ + struct TALER_Amount fee_melt; + + /** + * The original value of the coin. + */ + struct TALER_Amount original_value; + + /** + * Transfer private keys for each cut-and-choose dimension. + */ + struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA]; + + /** + * Timestamp indicating when coins of this denomination become invalid. + */ + struct GNUNET_TIME_Absolute deposit_valid_until; + + /** + * Denomination key of the original coin. + */ + struct TALER_DenominationPublicKey pub_key; + + /** + * Exchange's signature over the coin. + */ + struct TALER_DenominationSignature sig; + +}; + + +/** + * Coin-specific information about the fresh coins we generate during + * a melt. + */ +struct FreshCoin +{ + + /** + * Private key of the coin. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * Blinding key used for blinding during blind signing. + */ + struct TALER_DenominationBlindingKey blinding_key; + +}; + + +/** + * Melt data in non-serialized format for convenient processing. + */ +struct MeltData +{ + + /** + * Hash over the melting session. + */ + struct GNUNET_HashCode melt_session_hash; + + /** + * Link secrets for each cut-and-choose dimension. + */ + struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA]; + + /** + * Number of coins we are melting + */ + uint16_t num_melted_coins; + + /** + * Number of coins we are creating + */ + uint16_t num_fresh_coins; + + /** + * Information about the melted coins in an array of length @e + * num_melted_coins. + */ + struct MeltedCoin *melted_coins; + + /** + * Array of @e num_fresh_coins denomination keys for the coins to be + * freshly exchangeed. + */ + struct TALER_DenominationPublicKey *fresh_pks; + + /** + * Arrays of @e num_fresh_coins with information about the fresh + * coins to be created, for each cut-and-choose dimension. + */ + struct FreshCoin *fresh_coins[TALER_CNC_KAPPA]; +}; + + +/** + * Free all information associated with a melted coin session. + * + * @param mc melted coin to release, the pointer itself is NOT + * freed (as it is typically not allocated by itself) + */ +static void +free_melted_coin (struct MeltedCoin *mc) +{ + if (NULL == mc) + return; + if (NULL != mc->pub_key.rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (mc->pub_key.rsa_public_key); + if (NULL != mc->sig.rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (mc->sig.rsa_signature); +} + + +/** + * Free all information associated with a fresh coin. + * + * @param fc fresh coin to release, the pointer itself is NOT + * freed (as it is typically not allocated by itself) + */ +static void +free_fresh_coin (struct FreshCoin *fc) +{ + if (NULL == fc) + return; + if (NULL != fc->blinding_key.rsa_blinding_key) + GNUNET_CRYPTO_rsa_blinding_key_free (fc->blinding_key.rsa_blinding_key); +} + + +/** + * Free all information associated with a melting session. Note + * that we allow the melting session to be only partially initialized, + * as we use this function also when freeing melt data that was not + * fully initialized (i.e. due to failures in #deserialize_melt_data()). + * + * @param md melting data to release, the pointer itself is NOT + * freed (as it is typically not allocated by itself) + */ +static void +free_melt_data (struct MeltData *md) +{ + unsigned int i; + unsigned int j; + + if (NULL != md->melted_coins) + { + for (i=0;i<md->num_melted_coins;i++) + free_melted_coin (&md->melted_coins[i]); + GNUNET_free (md->melted_coins); + } + if (NULL != md->fresh_pks) + { + for (i=0;i<md->num_fresh_coins;i++) + if (NULL != md->fresh_pks[i].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key); + GNUNET_free (md->fresh_pks); + } + + for (i=0;i<TALER_CNC_KAPPA;i++) + { + for (j=0;j<md->num_fresh_coins;j++) + free_fresh_coin (&md->fresh_coins[i][j]); + GNUNET_free (md->fresh_coins[i]); + } + /* Finally, clean up a bit... + (NOTE: compilers might optimize this away, so this is + not providing any strong assurances that the key material + is purged.) */ + memset (md, + 0, + sizeof (struct MeltData)); +} + + +/** + * Serialize information about a coin we are melting. + * + * @param mc information to serialize + * @param buf buffer to write data in, NULL to just compute + * required size + * @param off offeset at @a buf to use + * @return number of bytes written to @a buf at @a off, or if + * @a buf is NULL, number of bytes required; 0 on error + */ +static size_t +serialize_melted_coin (const struct MeltedCoin *mc, + char *buf, + size_t off) +{ + struct MeltedCoinP mcp; + unsigned int i; + char *pbuf; + size_t pbuf_size; + char *sbuf; + size_t sbuf_size; + + sbuf_size = GNUNET_CRYPTO_rsa_signature_encode (mc->sig.rsa_signature, + &sbuf); + pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (mc->pub_key.rsa_public_key, + &pbuf); + if (NULL == buf) + { + GNUNET_free (sbuf); + GNUNET_free (pbuf); + return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size; + } + if ( (sbuf_size > UINT16_MAX) || + (pbuf_size > UINT16_MAX) ) + { + GNUNET_break (0); + return 0; + } + mcp.coin_priv = mc->coin_priv; + TALER_amount_hton (&mcp.melt_amount_with_fee, + &mc->melt_amount_with_fee); + TALER_amount_hton (&mcp.fee_melt, + &mc->fee_melt); + TALER_amount_hton (&mcp.original_value, + &mc->original_value); + for (i=0;i<TALER_CNC_KAPPA;i++) + mcp.transfer_priv[i] = mc->transfer_priv[i]; + mcp.deposit_valid_until = GNUNET_TIME_absolute_hton (mc->deposit_valid_until); + mcp.pbuf_size = htons ((uint16_t) pbuf_size); + mcp.sbuf_size = htons ((uint16_t) sbuf_size); + memcpy (&buf[off], + &mcp, + sizeof (struct MeltedCoinP)); + memcpy (&buf[off + sizeof (struct MeltedCoinP)], + pbuf, + pbuf_size); + memcpy (&buf[off + sizeof (struct MeltedCoinP) + pbuf_size], + sbuf, + sbuf_size); + GNUNET_free (sbuf); + GNUNET_free (pbuf); + return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size; +} + + +/** + * Deserialize information about a coin we are melting. + * + * @param[out] mc information to deserialize + * @param buf buffer to read data from + * @param size number of bytes available at @a buf to use + * @param[out] ok set to #GNUNET_NO to report errors + * @return number of bytes read from @a buf, 0 on error + */ +static size_t +deserialize_melted_coin (struct MeltedCoin *mc, + const char *buf, + size_t size, + int *ok) +{ + struct MeltedCoinP mcp; + unsigned int i; + size_t pbuf_size; + size_t sbuf_size; + size_t off; + + if (size < sizeof (struct MeltedCoinP)) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + memcpy (&mcp, + buf, + sizeof (struct MeltedCoinP)); + pbuf_size = ntohs (mcp.pbuf_size); + sbuf_size = ntohs (mcp.sbuf_size); + if (size < sizeof (struct MeltedCoinP) + pbuf_size + sbuf_size) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + off = sizeof (struct MeltedCoinP); + mc->pub_key.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_decode (&buf[off], + pbuf_size); + off += pbuf_size; + mc->sig.rsa_signature + = GNUNET_CRYPTO_rsa_signature_decode (&buf[off], + sbuf_size); + off += sbuf_size; + if ( (NULL == mc->pub_key.rsa_public_key) || + (NULL == mc->sig.rsa_signature) ) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + + mc->coin_priv = mcp.coin_priv; + TALER_amount_ntoh (&mc->melt_amount_with_fee, + &mcp.melt_amount_with_fee); + TALER_amount_ntoh (&mc->fee_melt, + &mcp.fee_melt); + TALER_amount_ntoh (&mc->original_value, + &mcp.original_value); + for (i=0;i<TALER_CNC_KAPPA;i++) + mc->transfer_priv[i] = mcp.transfer_priv[i]; + mc->deposit_valid_until = GNUNET_TIME_absolute_ntoh (mcp.deposit_valid_until); + return off; +} + + +/** + * Serialize information about a denomination key. + * + * @param dk information to serialize + * @param buf buffer to write data in, NULL to just compute + * required size + * @param off offeset at @a buf to use + * @return number of bytes written to @a buf at @a off, or if + * @a buf is NULL, number of bytes required + */ +static size_t +serialize_denomination_key (const struct TALER_DenominationPublicKey *dk, + char *buf, + size_t off) +{ + char *pbuf; + size_t pbuf_size; + uint32_t be; + + pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key, + &pbuf); + if (NULL == buf) + { + GNUNET_free (pbuf); + return pbuf_size + sizeof (uint32_t); + } + be = htonl ((uint32_t) pbuf_size); + memcpy (&buf[off], + &be, + sizeof (uint32_t)); + memcpy (&buf[off + sizeof (uint32_t)], + pbuf, + pbuf_size); + GNUNET_free (pbuf); + return pbuf_size + sizeof (uint32_t); +} + + +/** + * Deserialize information about a denomination key. + * + * @param[out] dk information to deserialize + * @param buf buffer to read data from + * @param size number of bytes available at @a buf to use + * @param[out] ok set to #GNUNET_NO to report errors + * @return number of bytes read from @a buf, 0 on error + */ +static size_t +deserialize_denomination_key (struct TALER_DenominationPublicKey *dk, + const char *buf, + size_t size, + int *ok) +{ + size_t pbuf_size; + uint32_t be; + + if (size < sizeof (uint32_t)) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + memcpy (&be, + buf, + sizeof (uint32_t)); + pbuf_size = ntohl (be); + if (size < sizeof (uint32_t) + pbuf_size) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + dk->rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)], + pbuf_size); + + if (NULL == dk->rsa_public_key) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + return sizeof (uint32_t) + pbuf_size; +} + + +/** + * Serialize information about a fresh coin we are generating. + * + * @param fc information to serialize + * @param buf buffer to write data in, NULL to just compute + * required size + * @param off offeset at @a buf to use + * @return number of bytes written to @a buf at @a off, or if + * @a buf is NULL, number of bytes required + */ +static size_t +serialize_fresh_coin (const struct FreshCoin *fc, + char *buf, + size_t off) +{ + struct FreshCoinP fcp; + char *bbuf; + size_t bbuf_size; + + bbuf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (fc->blinding_key.rsa_blinding_key, + &bbuf); + if (NULL == buf) + { + GNUNET_free (bbuf); + return sizeof (struct FreshCoinP) + bbuf_size; + } + fcp.coin_priv = fc->coin_priv; + fcp.bbuf_size = htonl ((uint32_t) bbuf_size); + memcpy (&buf[off], + &fcp, + sizeof (struct FreshCoinP)); + memcpy (&buf[off + sizeof (struct FreshCoinP)], + bbuf, + bbuf_size); + GNUNET_free (bbuf); + return sizeof (struct FreshCoinP) + bbuf_size; +} + + +/** + * Deserialize information about a fresh coin we are generating. + * + * @param[out] fc information to deserialize + * @param buf buffer to read data from + * @param size number of bytes available at @a buf to use + * @param[out] ok set to #GNUNET_NO to report errors + * @return number of bytes read from @a buf, 0 on error + */ +static size_t +deserialize_fresh_coin (struct FreshCoin *fc, + const char *buf, + size_t size, + int *ok) +{ + struct FreshCoinP fcp; + size_t bbuf_size; + + if (size < sizeof (struct FreshCoinP)) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + memcpy (&fcp, + buf, + sizeof (struct FreshCoinP)); + bbuf_size = ntohl (fcp.bbuf_size); + if (size < sizeof (struct FreshCoinP) + bbuf_size) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + fc->blinding_key.rsa_blinding_key + = GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct FreshCoinP)], + bbuf_size); + if (NULL == fc->blinding_key.rsa_blinding_key) + { + GNUNET_break (0); + *ok = GNUNET_NO; + return 0; + } + fc->coin_priv = fcp.coin_priv; + return sizeof (struct FreshCoinP) + bbuf_size; +} + + +/** + * Serialize melt data. + * + * @param md data to serialize + * @param[out] res_size size of buffer returned + * @return serialized melt data + */ +static char * +serialize_melt_data (const struct MeltData *md, + size_t *res_size) +{ + size_t size; + size_t asize; + char *buf; + unsigned int i; + unsigned int j; + + size = 0; + asize = (size_t) -1; /* make the compiler happy */ + buf = NULL; + /* we do 2 iterations, #1 to determine total size, #2 to + actually construct the buffer */ + do { + if (0 == size) + { + size = sizeof (struct MeltDataP); + } + else + { + struct MeltDataP *mdp; + + buf = GNUNET_malloc (size); + asize = size; /* just for invariant check later */ + size = sizeof (struct MeltDataP); + mdp = (struct MeltDataP *) buf; + mdp->melt_session_hash = md->melt_session_hash; + for (i=0;i<TALER_CNC_KAPPA;i++) + mdp->link_secrets[i] = md->link_secrets[i]; + mdp->num_melted_coins = htons (md->num_melted_coins); + mdp->num_fresh_coins = htons (md->num_fresh_coins); + } + for (i=0;i<md->num_melted_coins;i++) + size += serialize_melted_coin (&md->melted_coins[i], + buf, + size); + for (i=0;i<md->num_fresh_coins;i++) + size += serialize_denomination_key (&md->fresh_pks[i], + buf, + size); + for (i=0;i<TALER_CNC_KAPPA;i++) + for(j=0;j<md->num_fresh_coins;j++) + size += serialize_fresh_coin (&md->fresh_coins[i][j], + buf, + size); + } while (NULL == buf); + GNUNET_assert (size == asize); + *res_size = size; + return buf; +} + + +/** + * Deserialize melt data. + * + * @param buf serialized data + * @param buf_size size of @a buf + * @return deserialized melt data, NULL on error + */ +static struct MeltData * +deserialize_melt_data (const char *buf, + size_t buf_size) +{ + struct MeltData *md; + struct MeltDataP mdp; + unsigned int i; + unsigned int j; + size_t off; + int ok; + + if (buf_size < sizeof (struct MeltDataP)) + return NULL; + memcpy (&mdp, + buf, + sizeof (struct MeltDataP)); + md = GNUNET_new (struct MeltData); + md->melt_session_hash = mdp.melt_session_hash; + for (i=0;i<TALER_CNC_KAPPA;i++) + md->link_secrets[i] = mdp.link_secrets[i]; + md->num_melted_coins = ntohs (mdp.num_melted_coins); + md->num_fresh_coins = ntohs (mdp.num_fresh_coins); + md->melted_coins = GNUNET_new_array (md->num_melted_coins, + struct MeltedCoin); + md->fresh_pks = GNUNET_new_array (md->num_fresh_coins, + struct TALER_DenominationPublicKey); + for (i=0;i<TALER_CNC_KAPPA;i++) + md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins, + struct FreshCoin); + off = sizeof (struct MeltDataP); + ok = GNUNET_YES; + for (i=0;(i<md->num_melted_coins)&&(GNUNET_YES == ok);i++) + off += deserialize_melted_coin (&md->melted_coins[i], + &buf[off], + buf_size - off, + &ok); + for (i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++) + off += deserialize_denomination_key (&md->fresh_pks[i], + &buf[off], + buf_size - off, + &ok); + + for (i=0;i<TALER_CNC_KAPPA;i++) + for(j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++) + off += deserialize_fresh_coin (&md->fresh_coins[i][j], + &buf[off], + buf_size - off, + &ok); + if (off != buf_size) + { + GNUNET_break (0); + ok = GNUNET_NO; + } + if (GNUNET_YES != ok) + { + free_melt_data (md); + GNUNET_free (md); + return NULL; + } + return md; +} + + +/** + * Setup information for a fresh coin. + * + * @param[out] fc value to initialize + * @param pk denomination information for the fresh coin + */ +static void +setup_fresh_coin (struct FreshCoin *fc, + const struct TALER_EXCHANGE_DenomPublicKey *pk) +{ + struct GNUNET_CRYPTO_EddsaPrivateKey *epk; + unsigned int len; + + epk = GNUNET_CRYPTO_eddsa_key_create (); + fc->coin_priv.eddsa_priv = *epk; + GNUNET_free (epk); + len = GNUNET_CRYPTO_rsa_public_key_len (pk->key.rsa_public_key); + fc->blinding_key.rsa_blinding_key + = GNUNET_CRYPTO_rsa_blinding_key_create (len); +} + + +/** + * Melt (partially spent) coins to obtain fresh coins that are + * unlinkable to the original coin(s). Note that melting more + * than one coin in a single request will make those coins linkable, + * so the safest operation only melts one coin at a time. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, is operation does + * not actually initiate the request. Instead, it generates a buffer + * which the caller must store before proceeding with the actual call + * to #TALER_EXCHANGE_refresh_melt() that will generate the request. + * + * This function does verify that the given request data is internally + * consistent. However, the @a melts_sigs are only verified if + * @a check_sigs is set to #GNUNET_YES, as this may be relatively + * expensive and should be redundant. + * + * Aside from some non-trivial cryptographic operations that might + * take a bit of CPU time to complete, this function returns + * its result immediately and does not start any asynchronous + * processing. This function is also thread-safe. + * + * @param num_melts number of coins that are being melted (typically 1) + * @param melt_privs array of @a num_melts private keys of the coins to melt + * @param melt_amounts array of @a num_melts amounts specifying how much + * each coin will contribute to the melt (including fee) + * @param melt_sigs array of @a num_melts signatures affirming the + * validity of the public keys corresponding to the + * @a melt_privs private keys + * @param melt_pks array of @a num_melts denomination key information + * records corresponding to the @a melt_sigs + * validity of the keys + * @param check_sigs verify the validity of the signatures of @a melt_sigs + * @param fresh_pks_len length of the @a pks array + * @param fresh_pks array of @a pks_len denominations of fresh coins to create + * @param[out] res_size set to the size of the return value, or 0 on error + * @return NULL + * if the inputs are invalid (i.e. denomination key not with this exchange). + * Otherwise, pointer to a buffer of @a res_size to store persistently + * before proceeding to #TALER_EXCHANGE_refresh_melt(). + * Non-null results should be freed using #GNUNET_free(). + */ +char * +TALER_EXCHANGE_refresh_prepare (unsigned int num_melts, + const struct TALER_CoinSpendPrivateKeyP *melt_privs, + const struct TALER_Amount *melt_amounts, + const struct TALER_DenominationSignature *melt_sigs, + const struct TALER_EXCHANGE_DenomPublicKey *melt_pks, + int check_sigs, + unsigned int fresh_pks_len, + const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks, + size_t *res_size) +{ + struct MeltData md; + char *buf; + unsigned int i; + unsigned int j; + struct GNUNET_HashContext *hash_context; + + /* build up melt data structure */ + for (i=0;i<TALER_CNC_KAPPA;i++) + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, + &md.link_secrets[i], + sizeof (struct TALER_LinkSecretP)); + md.num_melted_coins = num_melts; + md.num_fresh_coins = fresh_pks_len; + md.melted_coins = GNUNET_new_array (num_melts, + struct MeltedCoin); + for (i=0;i<num_melts;i++) + { + md.melted_coins[i].coin_priv = melt_privs[i]; + md.melted_coins[i].melt_amount_with_fee = melt_amounts[i]; + md.melted_coins[i].fee_melt = melt_pks[i].fee_refresh; + md.melted_coins[i].original_value = melt_pks[i].value; + for (j=0;j<TALER_CNC_KAPPA;j++) + { + struct GNUNET_CRYPTO_EcdhePrivateKey *tpk; + + tpk = GNUNET_CRYPTO_ecdhe_key_create (); + md.melted_coins[i].transfer_priv[j].ecdhe_priv = *tpk; + GNUNET_free (tpk); + } + md.melted_coins[i].deposit_valid_until + = melt_pks[i].deposit_valid_until; + md.melted_coins[i].pub_key.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_dup (melt_pks[i].key.rsa_public_key); + md.melted_coins[i].sig.rsa_signature + = GNUNET_CRYPTO_rsa_signature_dup (melt_sigs[i].rsa_signature); + } + md.fresh_pks = GNUNET_new_array (fresh_pks_len, + struct TALER_DenominationPublicKey); + for (i=0;i<fresh_pks_len;i++) + md.fresh_pks[i].rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key); + for (i=0;i<TALER_CNC_KAPPA;i++) + { + md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len, + struct FreshCoin); + for (j=0;j<fresh_pks_len;j++) + setup_fresh_coin (&md.fresh_coins[i][j], + &fresh_pks[j]); + } + + /* now compute melt session hash */ + hash_context = GNUNET_CRYPTO_hash_context_start (); + for (i=0;i<fresh_pks_len;i++) + { + char *buf; + size_t buf_size; + + buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key, + &buf); + GNUNET_CRYPTO_hash_context_read (hash_context, + buf, + buf_size); + GNUNET_free (buf); + } + for (i=0;i<num_melts;i++) + { + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AmountNBO melt_amount; + + GNUNET_CRYPTO_eddsa_key_get_public (&melt_privs[i].eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash_context_read (hash_context, + &coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)); + TALER_amount_hton (&melt_amount, + &melt_amounts[i]); + GNUNET_CRYPTO_hash_context_read (hash_context, + &melt_amount, + sizeof (struct TALER_AmountNBO)); + + } + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + for (j = 0; j < fresh_pks_len; j++) + { + const struct FreshCoin *fc; /* coin this is about */ + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode coin_hash; + char *coin_ev; /* blinded message to be signed (in envelope) for each coin */ + size_t coin_ev_size; + struct TALER_RefreshLinkDecrypted rld; + struct TALER_RefreshLinkEncrypted *rle; + char *link_enc; /* encrypted link data */ + size_t link_enc_size; + + fc = &md.fresh_coins[i][j]; + GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), + &coin_hash); + coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash, + fc->blinding_key.rsa_blinding_key, + md.fresh_pks[j].rsa_public_key, + &coin_ev); + GNUNET_CRYPTO_hash_context_read (hash_context, + coin_ev, + coin_ev_size); + GNUNET_free (coin_ev); + + rld.coin_priv = fc->coin_priv; + rld.blinding_key = fc->blinding_key; + rle = TALER_refresh_encrypt (&rld, + &md.link_secrets[i]); + link_enc = TALER_refresh_link_encrypted_encode (rle, + &link_enc_size); + + GNUNET_CRYPTO_hash_context_read (hash_context, + link_enc, + link_enc_size); + GNUNET_free (link_enc); + } + } + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + for (j = 0; j < num_melts; j++) + { + struct TALER_RefreshCommitLinkP rcl; + struct TALER_TransferSecretP trans_sec; + + GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coins[j].transfer_priv[i].ecdhe_priv, + &rcl.transfer_pub.ecdhe_pub); + TALER_link_derive_transfer_secret (&melt_privs[j], + &md.melted_coins[j].transfer_priv[i], + &trans_sec); + TALER_transfer_encrypt (&md.link_secrets[i], + &trans_sec, + &rcl.shared_secret_enc); + GNUNET_CRYPTO_hash_context_read (hash_context, + &rcl, + sizeof (struct TALER_RefreshCommitLinkP)); + } + } + + GNUNET_CRYPTO_hash_context_finish (hash_context, + &md.melt_session_hash); + + /* finally, serialize everything */ + buf = serialize_melt_data (&md, + res_size); + free_melt_data (&md); + return buf; +} + + +/* ********************* /refresh/melt ***************************** */ + + +/** + * @brief A /refresh/melt Handle + */ +struct TALER_EXCHANGE_RefreshMeltHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with refresh melt failure results. + */ + TALER_EXCHANGE_RefreshMeltCallback melt_cb; + + /** + * Closure for @e result_cb and @e melt_failure_cb. + */ + void *melt_cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Actual information about the melt operation. + */ + struct MeltData *md; +}; + + +/** + * Verify that the signature on the "200 OK" response + * from the exchange is valid. + * + * @param rmh melt handle + * @param json json reply with the signature + * @param[out] noreveal_index set to the noreveal index selected by the exchange + * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not + */ +static int +verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh, + json_t *json, + uint16_t *noreveal_index) +{ + struct TALER_ExchangeSignatureP exchange_sig; + struct TALER_ExchangePublicKeyP exchange_pub; + const struct TALER_EXCHANGE_Keys *key_state; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("exchange_sig", &exchange_sig), + MAJ_spec_fixed_auto ("exchange_pub", &exchange_pub), + MAJ_spec_uint16 ("noreveal_index", noreveal_index), + MAJ_spec_end + }; + struct TALER_RefreshMeltConfirmationPS confirm; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* check that exchange signing key is permitted */ + key_state = TALER_EXCHANGE_get_keys (rmh->exchange); + if (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_state, + &exchange_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* check that noreveal index is in permitted range */ + if (TALER_CNC_KAPPA <= *noreveal_index) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* verify signature by exchange */ + confirm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT); + confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS)); + confirm.session_hash = rmh->md->melt_session_hash; + confirm.noreveal_index = htons (*noreveal_index); + confirm.reserved = htons (0); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT, + &confirm.purpose, + &exchange_sig.eddsa_signature, + &exchange_pub.eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Verify that the signatures on the "403 FORBIDDEN" response from the + * exchange demonstrating customer double-spending are valid. + * + * @param rmh melt handle + * @param json json reply with the signature(s) and transaction history + * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not + */ +static int +verify_refresh_melt_signature_forbidden (struct TALER_EXCHANGE_RefreshMeltHandle *rmh, + json_t *json) +{ + json_t *history; + struct TALER_Amount original_value; + struct TALER_Amount melt_value_with_fee; + struct TALER_Amount total; + struct TALER_CoinSpendPublicKeyP coin_pub; + unsigned int i; + struct MAJ_Specification spec[] = { + MAJ_spec_json ("history", &history), + MAJ_spec_fixed_auto ("coin_pub", &coin_pub), + MAJ_spec_amount ("original_value", &original_value), + MAJ_spec_amount ("requested_value", &melt_value_with_fee), + MAJ_spec_end + }; + const struct MeltedCoin *mc; + + /* parse JSON reply */ + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* Find out which coin was deemed problematic by the exchange */ + mc = NULL; + for (i=0;i<rmh->md->num_melted_coins;i++) + { + if (0 == TALER_amount_cmp (&melt_value_with_fee, + &rmh->md->melted_coins[i].melt_amount_with_fee)) + { + struct TALER_CoinSpendPublicKeyP mc_pub; + + GNUNET_CRYPTO_eddsa_key_get_public (&rmh->md->melted_coins[i].coin_priv.eddsa_priv, + &mc_pub.eddsa_pub); + if (0 == memcmp (&mc_pub, + &coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP))) + { + mc = &rmh->md->melted_coins[i]; + break; + } + } + } + if (NULL == mc) + { + /* coin not found in our original request */ + GNUNET_break_op (0); + json_decref (history); + return GNUNET_SYSERR; + } + + /* check basic coin properties */ + if (0 != TALER_amount_cmp (&original_value, + &mc->original_value)) + { + /* We disagree on the value of the coin */ + GNUNET_break_op (0); + json_decref (history); + return GNUNET_SYSERR; + } + if (0 != TALER_amount_cmp (&melt_value_with_fee, + &mc->melt_amount_with_fee)) + { + /* We disagree on the value of the coin */ + GNUNET_break_op (0); + json_decref (history); + return GNUNET_SYSERR; + } + + /* verify coin history */ + history = json_object_get (json, + "history"); + if (GNUNET_OK != + TALER_EXCHANGE_verify_coin_history_ (original_value.currency, + &coin_pub, + history, + &total)) + { + GNUNET_break_op (0); + json_decref (history); + return GNUNET_SYSERR; + } + json_decref (history); + + /* check if melt operation was really too expensive given history */ + if (GNUNET_OK != + TALER_amount_add (&total, + &total, + &melt_value_with_fee)) + { + /* clearly not OK if our transaction would have caused + the overflow... */ + return GNUNET_OK; + } + + if (0 >= TALER_amount_cmp (&total, + &original_value)) + { + /* transaction should have still fit */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + + /* everything OK, valid proof of double-spending was provided */ + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /refresh/melt request. + * + * @param cls the `struct TALER_EXCHANGE_RefreshMeltHandle` + * @param eh the curl request handle + */ +static void +handle_refresh_melt_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_RefreshMeltHandle *rmh = cls; + long response_code; + json_t *json; + uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */ + + rmh->job = NULL; + json = MAC_download_get_result (&rmh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + if (GNUNET_OK != + verify_refresh_melt_signature_ok (rmh, + json, + &noreveal_index)) + { + GNUNET_break_op (0); + response_code = 0; + } + if (NULL != rmh->melt_cb) + { + rmh->melt_cb (rmh->melt_cb_cls, + response_code, + noreveal_index, + json); + rmh->melt_cb = NULL; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_FORBIDDEN: + /* Double spending; check signatures on transaction history */ + if (GNUNET_OK != + verify_refresh_melt_signature_forbidden (rmh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, exchange says one of the signatures is + invalid; assuming we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != rmh->melt_cb) + rmh->melt_cb (rmh->melt_cb_cls, + response_code, + UINT16_MAX, + json); + json_decref (json); + TALER_EXCHANGE_refresh_melt_cancel (rmh); +} + + +/** + * Convert a coin to be melted to the respective JSON encoding. + * + * @param melt_session_hash session hash to use + * @param mc coin to be melted + * @return JSON encoding of the melting request + */ +static json_t * +melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash, + const struct MeltedCoin *mc) +{ + struct TALER_CoinSpendSignatureP confirm_sig; + struct TALER_RefreshMeltCoinAffirmationPS melt; + + melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); + melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); + melt.session_hash = *melt_session_hash; + TALER_amount_hton (&melt.amount_with_fee, + &mc->melt_amount_with_fee); + TALER_amount_hton (&melt.melt_fee, + &mc->fee_melt); + GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv, + &melt.coin_pub.eddsa_pub); + GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv, + &melt.purpose, + &confirm_sig.eddsa_signature); + return json_pack ("{s:o, s:o, s:o, s:o, s:o}", + "coin_pub", + TALER_json_from_data (&melt.coin_pub, + sizeof (melt.coin_pub)), + "denom_pub", + TALER_json_from_rsa_public_key (mc->pub_key.rsa_public_key), + "denom_sig", + TALER_json_from_rsa_signature (mc->sig.rsa_signature), + "confirm_sig", + TALER_json_from_data (&confirm_sig, + sizeof (confirm_sig)), + "value_with_fee", + TALER_json_from_amount (&mc->melt_amount_with_fee)); +} + + +/** + * Submit a melt request to the exchange and get the exchange's + * response. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, the provided + * argument should have been constructed using + * #TALER_EXCHANGE_refresh_prepare and committed to persistent storage + * prior to calling this function. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param refresh_data_length size of the @a refresh_data (returned + * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare()) + * @param refresh_data the refresh data as returned from + #TALER_EXCHANGE_refresh_prepare()) + * @param melt_cb the callback to call with the result + * @param melt_cb_cls closure for @a melt_cb + * @return a handle for this request; NULL if the argument was invalid. + * In this case, neither callback will be called. + */ +struct TALER_EXCHANGE_RefreshMeltHandle * +TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange, + size_t refresh_data_length, + const char *refresh_data, + TALER_EXCHANGE_RefreshMeltCallback melt_cb, + void *melt_cb_cls) +{ + json_t *melt_obj; + json_t *new_denoms; + json_t *melt_coins; + json_t *coin_evs; + json_t *transfer_pubs; + json_t *secret_encs; + json_t *link_encs; + json_t *tmp; + struct TALER_EXCHANGE_RefreshMeltHandle *rmh; + CURL *eh; + struct TALER_EXCHANGE_Context *ctx; + struct MeltData *md; + unsigned int i; + unsigned int j; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + md = deserialize_melt_data (refresh_data, + refresh_data_length); + if (NULL == md) + { + GNUNET_break (0); + return NULL; + } + + /* build JSON request, each of the 6 arrays first */ + new_denoms = json_array (); + melt_coins = json_array (); + coin_evs = json_array (); + transfer_pubs = json_array (); + secret_encs = json_array (); + link_encs = json_array (); + for (i=0;i<md->num_melted_coins;i++) + { + const struct MeltedCoin *mc = &md->melted_coins[i]; + + /* now melt_coins */ + json_array_append (melt_coins, + melted_coin_to_json (&md->melt_session_hash, + mc)); + } + + /* now transfer_pubs */ + for (j=0;j<TALER_CNC_KAPPA;j++) + { + tmp = json_array (); + for (i=0;i<md->num_melted_coins;i++) + { + const struct MeltedCoin *mc = &md->melted_coins[i]; + struct TALER_TransferPublicKeyP transfer_pub; + + GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv, + &transfer_pub.ecdhe_pub); + json_array_append (tmp, + TALER_json_from_data (&transfer_pub, + sizeof (transfer_pub))); + } + json_array_append (transfer_pubs, + tmp); + } + + /* now secret_encs */ + for (j=0;j<TALER_CNC_KAPPA;j++) + { + tmp = json_array (); + for (i=0;i<md->num_melted_coins;i++) + { + const struct MeltedCoin *mc = &md->melted_coins[i]; + struct TALER_EncryptedLinkSecretP els; + struct TALER_TransferSecretP trans_sec; + + TALER_link_derive_transfer_secret (&mc->coin_priv, + &mc->transfer_priv[j], + &trans_sec); + GNUNET_assert (GNUNET_OK == + TALER_transfer_encrypt (&md->link_secrets[j], + &trans_sec, + &els)); + json_array_append (tmp, + TALER_json_from_data (&els, + sizeof (els))); + } + json_array_append (secret_encs, + tmp); + } + + /* now new_denoms */ + for (i=0;i<md->num_fresh_coins;i++) + { + json_array_append (new_denoms, + TALER_json_from_rsa_public_key + (md->fresh_pks[i].rsa_public_key)); + } + + /* now link_encs */ + for (j=0;j<TALER_CNC_KAPPA;j++) + { + tmp = json_array (); + for (i=0;i<md->num_fresh_coins;i++) + { + const struct FreshCoin *fc = &md->fresh_coins[j][i]; + struct TALER_RefreshLinkDecrypted rld; + struct TALER_RefreshLinkEncrypted *rle; + char *buf; + size_t buf_len; + + rld.coin_priv = fc->coin_priv; + rld.blinding_key = fc->blinding_key; + rle = TALER_refresh_encrypt (&rld, + &md->link_secrets[j]); + GNUNET_assert (NULL != rle); + buf = TALER_refresh_link_encrypted_encode (rle, + &buf_len); + GNUNET_assert (NULL != buf); + json_array_append (tmp, + TALER_json_from_data (buf, + buf_len)); + GNUNET_free (buf); + GNUNET_free (rle); + } + json_array_append (link_encs, + tmp); + } + + /* now coin_evs */ + for (j=0;j<TALER_CNC_KAPPA;j++) + { + tmp = json_array (); + for (i=0;i<md->num_fresh_coins;i++) + { + const struct FreshCoin *fc = &md->fresh_coins[j][i]; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode coin_hash; + char *coin_ev; /* blinded message to be signed (in envelope) for each coin */ + size_t coin_ev_size; + + GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), + &coin_hash); + coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash, + fc->blinding_key.rsa_blinding_key, + md->fresh_pks[i].rsa_public_key, + &coin_ev); + json_array_append (tmp, + TALER_json_from_data (coin_ev, + coin_ev_size)); + GNUNET_free (coin_ev); + } + json_array_append (coin_evs, + tmp); + } + + /* finally, assemble main JSON request from constitutent arrays */ + melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", + "new_denoms", new_denoms, + "melt_coins", melt_coins, + "coin_evs", coin_evs, + "transfer_pubs", transfer_pubs, + "secret_encs", secret_encs, + "link_encs", link_encs); + + /* and now we can at last begin the actual request handling */ + rmh = GNUNET_new (struct TALER_EXCHANGE_RefreshMeltHandle); + rmh->exchange = exchange; + rmh->melt_cb = melt_cb; + rmh->melt_cb_cls = melt_cb_cls; + rmh->md = md; + rmh->url = MAH_path_to_url (exchange, + "/refresh/melt"); + + eh = curl_easy_init (); + GNUNET_assert (NULL != (rmh->json_enc = + json_dumps (melt_obj, + JSON_COMPACT))); + json_decref (melt_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + rmh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + rmh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (rmh->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &rmh->db)); + ctx = MAH_handle_to_context (exchange); + rmh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_refresh_melt_finished, + rmh); + return rmh; +} + + +/** + * Cancel a refresh execute request. This function cannot be used + * on a request handle if either callback was already invoked. + * + * @param rmh the refresh melt handle + */ +void +TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh) +{ + if (NULL != rmh->job) + { + MAC_job_cancel (rmh->job); + rmh->job = NULL; + } + GNUNET_free_non_null (rmh->db.buf); + free_melt_data (rmh->md); /* does not free 'md' itself */ + GNUNET_free (rmh->md); + GNUNET_free (rmh->url); + GNUNET_free (rmh->json_enc); + GNUNET_free (rmh); +} + + +/* ********************* /refresh/reveal ***************************** */ + + +/** + * @brief A /refresh/reveal Handle + */ +struct TALER_EXCHANGE_RefreshRevealHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_RefreshRevealCallback reveal_cb; + + /** + * Closure for @e reveal_cb. + */ + void *reveal_cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Actual information about the melt operation. + */ + struct MeltData *md; + + /** + * The index selected by the exchange in cut-and-choose to not be revealed. + */ + uint16_t noreveal_index; + +}; + + +/** + * We got a 200 OK response for the /refresh/reveal operation. + * Extract the coin signatures and return them to the caller. + * The signatures we get from the exchange is for the blinded value. + * Thus, we first must unblind them and then should verify their + * validity. + * + * If everything checks out, we return the unblinded signatures + * to the application via the callback. + * + * @param rrh operation handle + * @param json reply from the exchange + * @param[out] coin_privs array of length `num_fresh_coins`, initialized to contain private keys + * @param[out] sigs array of length `num_fresh_coins`, initialized to cointain RSA signatures + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static int +refresh_reveal_ok (struct TALER_EXCHANGE_RefreshRevealHandle *rrh, + json_t *json, + struct TALER_CoinSpendPrivateKeyP *coin_privs, + struct TALER_DenominationSignature *sigs) +{ + unsigned int i; + json_t *jsona; + struct MAJ_Specification spec[] = { + MAJ_spec_json ("ev_sigs", &jsona), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! json_is_array (jsona)) + { + /* We expected an array of coins */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (rrh->md->num_fresh_coins != json_array_size (jsona)) + { + /* Number of coins generated does not match our expectation */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + for (i=0;i<rrh->md->num_fresh_coins;i++) + { + const struct FreshCoin *fc; + struct TALER_DenominationPublicKey *pk; + json_t *jsonai; + struct GNUNET_CRYPTO_rsa_Signature *blind_sig; + struct GNUNET_CRYPTO_rsa_Signature *sig; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode coin_hash; + + struct MAJ_Specification spec[] = { + MAJ_spec_rsa_signature ("ev_sig", &blind_sig), + MAJ_spec_end + }; + + fc = &rrh->md->fresh_coins[rrh->noreveal_index][i]; + pk = &rrh->md->fresh_pks[i]; + jsonai = json_array_get (jsona, i); + GNUNET_assert (NULL != jsonai); + + if (GNUNET_OK != + MAJ_parse_json (jsonai, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* unblind the signature */ + sig = GNUNET_CRYPTO_rsa_unblind (blind_sig, + fc->blinding_key.rsa_blinding_key, + pk->rsa_public_key); + GNUNET_CRYPTO_rsa_signature_free (blind_sig); + + /* verify the signature */ + GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), + &coin_hash); + + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (&coin_hash, + sig, + pk->rsa_public_key)) + { + GNUNET_break_op (0); + GNUNET_CRYPTO_rsa_signature_free (sig); + return GNUNET_SYSERR; + } + coin_privs[i] = fc->coin_priv; + sigs[i].rsa_signature = sig; + } + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /refresh/reveal request. + * + * @param cls the `struct TALER_EXCHANGE_RefreshHandle` + * @param eh the curl request handle + */ +static void +handle_refresh_reveal_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_RefreshRevealHandle *rrh = cls; + long response_code; + json_t *json; + + rrh->job = NULL; + json = MAC_download_get_result (&rrh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins]; + struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins]; + unsigned int i; + int ret; + + memset (sigs, 0, sizeof (sigs)); + ret = refresh_reveal_ok (rrh, + json, + coin_privs, + sigs); + if (GNUNET_OK != ret) + { + response_code = 0; + } + else + { + rrh->reveal_cb (rrh->reveal_cb_cls, + MHD_HTTP_OK, + rrh->md->num_fresh_coins, + coin_privs, + sigs, + json); + rrh->reveal_cb = NULL; + } + for (i=0;i<rrh->md->num_fresh_coins;i++) + if (NULL != sigs[i].rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature); + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_CONFLICT: + /* Nothing really to verify, exchange says our reveal is inconsitent + with our commitment, so either side is buggy; we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != rrh->reveal_cb) + rrh->reveal_cb (rrh->reveal_cb_cls, + response_code, + 0, NULL, NULL, + json); + json_decref (json); + TALER_EXCHANGE_refresh_reveal_cancel (rrh); +} + + +/** + * Submit a /refresh/reval request to the exchange and get the exchange's + * response. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, the provided + * arguments should have been committed to persistent storage + * prior to calling this function. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param refresh_data_length size of the @a refresh_data (returned + * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare()) + * @param refresh_data the refresh data as returned from + #TALER_EXCHANGE_refresh_prepare()) + * @param noreveal_index response from the exchange to the + * #TALER_EXCHANGE_refresh_melt() invocation + * @param reveal_cb the callback to call with the final result of the + * refresh operation + * @param reveal_cb_cls closure for the above callback + * @return a handle for this request; NULL if the argument was invalid. + * In this case, neither callback will be called. + */ +struct TALER_EXCHANGE_RefreshRevealHandle * +TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange, + size_t refresh_data_length, + const char *refresh_data, + uint16_t noreveal_index, + TALER_EXCHANGE_RefreshRevealCallback reveal_cb, + void *reveal_cb_cls) +{ + struct TALER_EXCHANGE_RefreshRevealHandle *rrh; + json_t *transfer_privs; + json_t *reveal_obj; + json_t *tmp; + CURL *eh; + struct TALER_EXCHANGE_Context *ctx; + struct MeltData *md; + unsigned int i; + unsigned int j; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + md = deserialize_melt_data (refresh_data, + refresh_data_length); + if (NULL == md) + { + GNUNET_break (0); + return NULL; + } + if (noreveal_index >= TALER_CNC_KAPPA) + { + /* We check this here, as it would be really bad to below just + disclose all the transfer keys. Note that this error should + have been caught way earlier when the exchange replied, but maybe + we had some internal corruption that changed the value... */ + GNUNET_break (0); + return NULL; + } + + /* build array of transfer private keys */ + transfer_privs = json_array (); + for (j=0;j<TALER_CNC_KAPPA;j++) + { + if (j == noreveal_index) + { + /* This is crucial: exclude the transfer key for the + noreval index! */ + continue; + } + tmp = json_array (); + for (i=0;i<md->num_melted_coins;i++) + { + const struct MeltedCoin *mc = &md->melted_coins[i]; + + json_array_append (tmp, + TALER_json_from_data (&mc->transfer_priv[j], + sizeof (struct TALER_TransferPrivateKeyP))); + } + json_array_append (transfer_privs, + tmp); + } + + /* build main JSON request */ + reveal_obj = json_pack ("{s:o, s:o}", + "session_hash", + TALER_json_from_data (&md->melt_session_hash, + sizeof (struct GNUNET_HashCode)), + "transfer_privs", + transfer_privs); + + /* finally, we can actually issue the request */ + rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshRevealHandle); + rrh->exchange = exchange; + rrh->noreveal_index = noreveal_index; + rrh->reveal_cb = reveal_cb; + rrh->reveal_cb_cls = reveal_cb_cls; + rrh->md = md; + rrh->url = MAH_path_to_url (rrh->exchange, + "/refresh/reveal"); + + eh = curl_easy_init (); + GNUNET_assert (NULL != (rrh->json_enc = + json_dumps (reveal_obj, + JSON_COMPACT))); + json_decref (reveal_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + rrh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + rrh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (rrh->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &rrh->db)); + ctx = MAH_handle_to_context (rrh->exchange); + rrh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_refresh_reveal_finished, + rrh); + return rrh; +} + + +/** + * Cancel a refresh reveal request. This function cannot be used + * on a request handle if the callback was already invoked. + * + * @param rrh the refresh reval handle + */ +void +TALER_EXCHANGE_refresh_reveal_cancel (struct TALER_EXCHANGE_RefreshRevealHandle *rrh) +{ + if (NULL != rrh->job) + { + MAC_job_cancel (rrh->job); + rrh->job = NULL; + } + GNUNET_free_non_null (rrh->db.buf); + GNUNET_free (rrh->url); + GNUNET_free (rrh->json_enc); + free_melt_data (rrh->md); /* does not free 'md' itself */ + GNUNET_free (rrh->md); + GNUNET_free (rrh); +} + + +/* end of exchange_api_refresh.c */ diff --git a/src/exchange-lib/exchange_api_refresh_link.c b/src/exchange-lib/exchange_api_refresh_link.c new file mode 100644 index 000000000..9576916bc --- /dev/null +++ b/src/exchange-lib/exchange_api_refresh_link.c @@ -0,0 +1,482 @@ +/* + This file is part of TALER + Copyright (C) 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_refresh_link.c + * @brief Implementation of the /refresh/link request of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief A /refresh/link Handle + */ +struct TALER_EXCHANGE_RefreshLinkHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_RefreshLinkCallback link_cb; + + /** + * Closure for @e cb. + */ + void *link_cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Private key of the coin, required to decode link information. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + +}; + + +/** + * Parse the provided linkage data from the "200 OK" response + * for one of the coins. + * + * @param rlh refresh link handle + * @param json json reply with the data for one coin + * @param trans_pub our transfer public key + * @param secret_enc encrypted key to decrypt link data + * @param[out] coin_priv where to return private coin key + * @param[out] sig where to return private coin signature + * @param[out] pub where to return the public key for the coin + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +parse_refresh_link_coin (const struct TALER_EXCHANGE_RefreshLinkHandle *rlh, + json_t *json, + const struct TALER_TransferPublicKeyP *trans_pub, + const struct TALER_EncryptedLinkSecretP *secret_enc, + struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_DenominationSignature *sig, + struct TALER_DenominationPublicKey *pub) +{ + void *link_enc; + size_t link_enc_size; + struct GNUNET_CRYPTO_rsa_Signature *bsig; + struct GNUNET_CRYPTO_rsa_PublicKey *rpub; + struct MAJ_Specification spec[] = { + MAJ_spec_varsize ("link_enc", &link_enc, &link_enc_size), + MAJ_spec_rsa_public_key ("denom_pub", &rpub), + MAJ_spec_rsa_signature ("ev_sig", &bsig), + MAJ_spec_end + }; + struct TALER_RefreshLinkEncrypted *rle; + struct TALER_RefreshLinkDecrypted *rld; + struct TALER_LinkSecretP secret; + + /* parse reply */ + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* decode and decrypt link data */ + rle = TALER_refresh_link_encrypted_decode (link_enc, + link_enc_size); + if (NULL == rle) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_link_decrypt_secret2 (secret_enc, + trans_pub, + &rlh->coin_priv, + &secret)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + rld = TALER_refresh_decrypt (rle, + &secret); + if (NULL == rld) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + + /* extract coin and signature */ + *coin_priv = rld->coin_priv; + sig->rsa_signature + = GNUNET_CRYPTO_rsa_unblind (bsig, + rld->blinding_key.rsa_blinding_key, + rpub); + + /* clean up */ + GNUNET_free (rld); + pub->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (rpub); + MAJ_parse_free (spec); + return GNUNET_OK; +} + + +/** + * Parse the provided linkage data from the "200 OK" response + * for one of the coins. + * + * @param[in,out] rlh refresh link handle (callback may be zero'ed out) + * @param json json reply with the data for one coin + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +parse_refresh_link_ok (struct TALER_EXCHANGE_RefreshLinkHandle *rlh, + json_t *json) +{ + unsigned int session; + unsigned int num_coins; + int ret; + + if (! json_is_array (json)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num_coins = 0; + /* Theoretically, a coin may have been melted repeatedly + into different sessions; so the response is an array + which contains information by melting session. That + array contains another array. However, our API returns + a single 1d array, so we flatten the 2d array that is + returned into a single array. Note that usually a coin + is melted at most once, and so we'll only run this + loop once for 'session=0' in most cases. + + num_coins tracks the size of the 1d array we return, + whilst 'i' and 'session' track the 2d array. */ + for (session=0;session<json_array_size (json); session++) + { + json_t *jsona; + struct MAJ_Specification spec[] = { + MAJ_spec_json ("new_coins", &jsona), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json_array_get (json, + session), + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! json_is_array (jsona)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + + /* count all coins over all sessions */ + num_coins += json_array_size (jsona); + MAJ_parse_free (spec); + } + /* Now that we know how big the 1d array is, allocate + and fill it. */ + { + unsigned int off_coin; /* index into 1d array */ + unsigned int i; + struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins]; + struct TALER_DenominationSignature sigs[num_coins]; + struct TALER_DenominationPublicKey pubs[num_coins]; + + memset (sigs, 0, sizeof (sigs)); + memset (pubs, 0, sizeof (pubs)); + off_coin = 0; + for (session=0;session<json_array_size (json); session++) + { + json_t *jsona; + struct TALER_TransferPublicKeyP trans_pub; + struct TALER_EncryptedLinkSecretP secret_enc; + struct MAJ_Specification spec[] = { + MAJ_spec_json ("new_coins", &jsona), + MAJ_spec_fixed_auto ("transfer_pub", &trans_pub), + MAJ_spec_fixed_auto ("secret_enc", &secret_enc), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json_array_get (json, + session), + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! json_is_array (jsona)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + + /* decode all coins */ + for (i=0;i<json_array_size (jsona);i++) + { + if (GNUNET_OK != + parse_refresh_link_coin (rlh, + json_array_get (jsona, + i), + &trans_pub, + &secret_enc, + &coin_privs[i+off_coin], + &sigs[i+off_coin], + &pubs[i+off_coin])) + { + GNUNET_break_op (0); + break; + } + } + /* check if we really got all, then invoke callback */ + off_coin += i; + if (i != json_array_size (jsona)) + { + GNUNET_break_op (0); + ret = GNUNET_SYSERR; + MAJ_parse_free (spec); + break; + } + MAJ_parse_free (spec); + } /* end of for (session) */ + + if (off_coin == num_coins) + { + rlh->link_cb (rlh->link_cb_cls, + MHD_HTTP_OK, + num_coins, + coin_privs, + sigs, + pubs, + json); + rlh->link_cb = NULL; + ret = GNUNET_OK; + } + else + { + GNUNET_break_op (0); + ret = GNUNET_SYSERR; + } + + /* clean up */ + for (i=0;i<off_coin;i++) + { + if (NULL != sigs[i].rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature); + if (NULL != pubs[i].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key); + } + } + return ret; +} + + +/** + * Function called when we're done processing the + * HTTP /refresh/link request. + * + * @param cls the `struct TALER_EXCHANGE_RefreshLinkHandle` + * @param eh the curl request handle + */ +static void +handle_refresh_link_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_RefreshLinkHandle *rlh = cls; + long response_code; + json_t *json; + + rlh->job = NULL; + json = MAC_download_get_result (&rlh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + if (GNUNET_OK != + parse_refresh_link_ok (rlh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, exchange says this coin was not melted; we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != rlh->link_cb) + rlh->link_cb (rlh->link_cb_cls, + response_code, + 0, NULL, NULL, NULL, + json); + json_decref (json); + TALER_EXCHANGE_refresh_link_cancel (rlh); +} + + +/** + * Submit a link request to the exchange and get the exchange's response. + * + * This API is typically not used by anyone, it is more a threat + * against those trying to receive a funds transfer by abusing the + * /refresh protocol. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param coin_priv private key to request link data for + * @param link_cb the callback to call with the useful result of the + * refresh operation the @a coin_priv was involved in (if any) + * @param link_cb_cls closure for @a link_cb + * @return a handle for this request + */ +struct TALER_EXCHANGE_RefreshLinkHandle * +TALER_EXCHANGE_refresh_link (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + TALER_EXCHANGE_RefreshLinkCallback link_cb, + void *link_cb_cls) +{ + struct TALER_EXCHANGE_RefreshLinkHandle *rlh; + CURL *eh; + struct TALER_EXCHANGE_Context *ctx; + struct TALER_CoinSpendPublicKeyP coin_pub; + char *pub_str; + char *arg_str; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + pub_str = GNUNET_STRINGS_data_to_string_alloc (&coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)); + GNUNET_asprintf (&arg_str, + "/refresh/link?coin_pub=%s", + pub_str); + GNUNET_free (pub_str); + + rlh = GNUNET_new (struct TALER_EXCHANGE_RefreshLinkHandle); + rlh->exchange = exchange; + rlh->link_cb = link_cb; + rlh->link_cb_cls = link_cb_cls; + rlh->coin_priv = *coin_priv; + rlh->url = MAH_path_to_url (exchange, arg_str); + GNUNET_free (arg_str); + + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + rlh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &rlh->db)); + ctx = MAH_handle_to_context (exchange); + rlh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_refresh_link_finished, + rlh); + return rlh; +} + + +/** + * Cancel a refresh link request. This function cannot be used + * on a request handle if the callback was already invoked. + * + * @param rlh the refresh link handle + */ +void +TALER_EXCHANGE_refresh_link_cancel (struct TALER_EXCHANGE_RefreshLinkHandle *rlh) +{ + if (NULL != rlh->job) + { + MAC_job_cancel (rlh->job); + rlh->job = NULL; + } + GNUNET_free_non_null (rlh->db.buf); + GNUNET_free (rlh->url); + GNUNET_free (rlh); +} + + +/* end of exchange_api_refresh_link.c */ diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c new file mode 100644 index 000000000..e694b8d95 --- /dev/null +++ b/src/exchange-lib/exchange_api_reserve.c @@ -0,0 +1,930 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_reserve.c + * @brief Implementation of the /reserve requests of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/* ********************** /reserve/status ********************** */ + +/** + * @brief A Withdraw Status Handle + */ +struct TALER_EXCHANGE_ReserveStatusHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_ReserveStatusResultCallback cb; + + /** + * Public key of the reserve we are querying. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + +}; + + +/** + * Parse history given in JSON format and return it in binary + * format. + * + * @param[in] history JSON array with the history + * @param reserve_pub public key of the reserve to inspect + * @param currency currency we expect the balance to be in + * @param[out] balance final balance + * @param history_length number of entries in @a history + * @param[out] rhistory array of length @a history_length, set to the + * parsed history entries + * @return #GNUNET_OK if history was valid and @a rhistory and @a balance + * were set, + * #GNUNET_SYSERR if there was a protocol violation in @a history + */ +static int +parse_reserve_history (json_t *history, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *currency, + struct TALER_Amount *balance, + unsigned int history_length, + struct TALER_EXCHANGE_ReserveHistory *rhistory) +{ + struct GNUNET_HashCode uuid[history_length]; + unsigned int uuid_off; + struct TALER_Amount total_in; + struct TALER_Amount total_out; + size_t off; + + TALER_amount_get_zero (currency, + &total_in); + TALER_amount_get_zero (currency, + &total_out); + uuid_off = 0; + for (off=0;off<history_length;off++) + { + json_t *transaction; + struct TALER_Amount amount; + const char *type; + struct MAJ_Specification hist_spec[] = { + MAJ_spec_string ("type", &type), + MAJ_spec_amount ("amount", + &amount), + /* 'wire' and 'signature' are optional depending on 'type'! */ + MAJ_spec_end + }; + + transaction = json_array_get (history, + off); + if (GNUNET_OK != + MAJ_parse_json (transaction, + hist_spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + rhistory[off].amount = amount; + + if (0 == strcasecmp (type, + "DEPOSIT")) + { + json_t *wire; + + rhistory[off].type = TALER_EXCHANGE_RTT_DEPOSIT; + if (GNUNET_OK != + TALER_amount_add (&total_in, + &total_in, + &amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + wire = json_object_get (transaction, + "wire"); + /* check 'wire' is a JSON object (no need to check wireformat, + but we do at least expect "some" JSON object here) */ + if ( (NULL == wire) || + (! json_is_object (wire)) ) + { + /* not even a JSON 'wire' specification, not acceptable */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + rhistory[off].details.wire_in_details = wire; + /* end type==DEPOSIT */ + } + else if (0 == strcasecmp (type, + "WITHDRAW")) + { + struct TALER_ReserveSignatureP sig; + struct TALER_WithdrawRequestPS withdraw_purpose; + struct TALER_Amount amount_from_purpose; + struct MAJ_Specification withdraw_spec[] = { + MAJ_spec_fixed_auto ("signature", + &sig), + MAJ_spec_fixed_auto ("details", + &withdraw_purpose), + MAJ_spec_end + }; + unsigned int i; + + rhistory[off].type = TALER_EXCHANGE_RTT_WITHDRAWAL; + if (GNUNET_OK != + MAJ_parse_json (transaction, + withdraw_spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* Check that the signature is a valid withdraw request */ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, + &withdraw_purpose.purpose, + &sig.eddsa_signature, + &reserve_pub->eddsa_pub)) + { + GNUNET_break_op (0); + MAJ_parse_free (withdraw_spec); + return GNUNET_SYSERR; + } + TALER_amount_ntoh (&amount_from_purpose, + &withdraw_purpose.amount_with_fee); + if (0 != TALER_amount_cmp (&amount, + &amount_from_purpose)) + { + GNUNET_break_op (0); + MAJ_parse_free (withdraw_spec); + return GNUNET_SYSERR; + } + rhistory[off].details.out_authorization_sig = json_object_get (transaction, + "signature"); + /* Check check that the same withdraw transaction + isn't listed twice by the exchange. We use the + "uuid" array to remember the hashes of all + purposes, and compare the hashes to find + duplicates. */ + GNUNET_CRYPTO_hash (&withdraw_purpose, + ntohl (withdraw_purpose.purpose.size), + &uuid[uuid_off]); + for (i=0;i<uuid_off;i++) + { + if (0 == memcmp (&uuid[uuid_off], + &uuid[i], + sizeof (struct GNUNET_HashCode))) + { + GNUNET_break_op (0); + MAJ_parse_free (withdraw_spec); + return GNUNET_SYSERR; + } + } + uuid_off++; + + if (GNUNET_OK != + TALER_amount_add (&total_out, + &total_out, + &amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + MAJ_parse_free (withdraw_spec); + return GNUNET_SYSERR; + } + /* end type==WITHDRAW */ + } + else + { + /* unexpected 'type', protocol incompatibility, complain! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + + /* check balance = total_in - total_out < withdraw-amount */ + if (GNUNET_SYSERR == + TALER_amount_subtract (balance, + &total_in, + &total_out)) + { + /* total_in < total_out, why did the exchange ever allow this!? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /reserve/status request. + * + * @param cls the `struct TALER_EXCHANGE_ReserveStatusHandle` + * @param eh curl handle of the request that finished + */ +static void +handle_reserve_status_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_ReserveStatusHandle *wsh = cls; + long response_code; + json_t *json; + + wsh->job = NULL; + json = MAC_download_get_result (&wsh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + /* TODO: move into separate function... */ + json_t *history; + unsigned int len; + struct TALER_Amount balance; + struct TALER_Amount balance_from_history; + struct MAJ_Specification spec[] = { + MAJ_spec_amount ("balance", &balance), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + history = json_object_get (json, + "history"); + if (NULL == history) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + len = json_array_size (history); + { + struct TALER_EXCHANGE_ReserveHistory rhistory[len]; + + if (GNUNET_OK != + parse_reserve_history (history, + &wsh->reserve_pub, + balance.currency, + &balance_from_history, + len, + rhistory)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + if (0 != + TALER_amount_cmp (&balance_from_history, + &balance)) + { + /* exchange cannot add up balances!? */ + GNUNET_break_op (0); + response_code = 0; + break; + } + wsh->cb (wsh->cb_cls, + response_code, + json, + &balance, + len, + rhistory); + wsh->cb = NULL; + } + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != wsh->cb) + wsh->cb (wsh->cb_cls, + response_code, + json, + NULL, + 0, NULL); + json_decref (json); + TALER_EXCHANGE_reserve_status_cancel (wsh); +} + + +/** + * Submit a request to obtain the transaction history of a reserve + * from the exchange. Note that while we return the full response to the + * caller for further processing, we do already verify that the + * response is well-formed (i.e. that signatures included in the + * response are all valid and add up to the balance). If the exchange's + * reply is not well-formed, we return an HTTP status code of zero to + * @a cb. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param reserve_pub public key of the reserve to inspect + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_ReserveStatusHandle * +TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_ReservePublicKeyP *reserve_pub, + TALER_EXCHANGE_ReserveStatusResultCallback cb, + void *cb_cls) +{ + struct TALER_EXCHANGE_ReserveStatusHandle *wsh; + struct TALER_EXCHANGE_Context *ctx; + CURL *eh; + char *pub_str; + char *arg_str; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub, + sizeof (struct TALER_ReservePublicKeyP)); + GNUNET_asprintf (&arg_str, + "/reserve/status?reserve_pub=%s", + pub_str); + GNUNET_free (pub_str); + wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle); + wsh->exchange = exchange; + wsh->cb = cb; + wsh->cb_cls = cb_cls; + wsh->reserve_pub = *reserve_pub; + wsh->url = MAH_path_to_url (exchange, + arg_str); + GNUNET_free (arg_str); + + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + wsh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &wsh->db)); + ctx = MAH_handle_to_context (exchange); + wsh->job = MAC_job_add (ctx, + eh, + GNUNET_NO, + &handle_reserve_status_finished, + wsh); + return wsh; +} + + +/** + * Cancel a withdraw status request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param wsh the withdraw status request handle + */ +void +TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh) +{ + if (NULL != wsh->job) + { + MAC_job_cancel (wsh->job); + wsh->job = NULL; + } + GNUNET_free_non_null (wsh->db.buf); + GNUNET_free (wsh->url); + GNUNET_free (wsh); +} + + +/* ********************** /reserve/withdraw ********************** */ + +/** + * @brief A Withdraw Sign Handle + */ +struct TALER_EXCHANGE_ReserveWithdrawHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * JSON encoding of the request to POST. + */ + char *json_enc; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_ReserveWithdrawResultCallback cb; + + /** + * Key used to blind the value. + */ + const struct TALER_DenominationBlindingKey *blinding_key; + + /** + * Denomination key we are withdrawing. + */ + const struct TALER_EXCHANGE_DenomPublicKey *pk; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Hash of the public key of the coin we are signing. + */ + struct GNUNET_HashCode c_hash; + + /** + * Public key of the reserve we are withdrawing from. + */ + struct TALER_ReservePublicKeyP reserve_pub; + +}; + + +/** + * We got a 200 OK response for the /reserve/withdraw operation. + * Extract the coin's signature and return it to the caller. + * The signature we get from the exchange is for the blinded value. + * Thus, we first must unblind it and then should verify its + * validity against our coin's hash. + * + * If everything checks out, we return the unblinded signature + * to the application via the callback. + * + * @param wsh operation handle + * @param json reply from the exchange + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static int +reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh, + json_t *json) +{ + struct GNUNET_CRYPTO_rsa_Signature *blind_sig; + struct GNUNET_CRYPTO_rsa_Signature *sig; + struct TALER_DenominationSignature dsig; + struct MAJ_Specification spec[] = { + MAJ_spec_rsa_signature ("ev_sig", &blind_sig), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + sig = GNUNET_CRYPTO_rsa_unblind (blind_sig, + wsh->blinding_key->rsa_blinding_key, + wsh->pk->key.rsa_public_key); + GNUNET_CRYPTO_rsa_signature_free (blind_sig); + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (&wsh->c_hash, + sig, + wsh->pk->key.rsa_public_key)) + { + GNUNET_break_op (0); + GNUNET_CRYPTO_rsa_signature_free (sig); + return GNUNET_SYSERR; + } + /* signature is valid, return it to the application */ + dsig.rsa_signature = sig; + wsh->cb (wsh->cb_cls, + MHD_HTTP_OK, + &dsig, + json); + /* make sure callback isn't called again after return */ + wsh->cb = NULL; + GNUNET_CRYPTO_rsa_signature_free (sig); + return GNUNET_OK; +} + + +/** + * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation. + * Check the signatures on the withdraw transactions in the provided + * history and that the balances add up. We don't do anything directly + * with the information, as the JSON will be returned to the application. + * However, our job is ensuring that the exchange followed the protocol, and + * this in particular means checking all of the signatures in the history. + * + * @param wsh operation handle + * @param json reply from the exchange + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static int +reserve_withdraw_payment_required (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh, + json_t *json) +{ + struct TALER_Amount balance; + struct TALER_Amount balance_from_history; + struct TALER_Amount requested_amount; + json_t *history; + size_t len; + struct MAJ_Specification spec[] = { + MAJ_spec_amount ("balance", &balance), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + history = json_object_get (json, + "history"); + if (NULL == history) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + /* go over transaction history and compute + total incoming and outgoing amounts */ + len = json_array_size (history); + { + struct TALER_EXCHANGE_ReserveHistory rhistory[len]; + + if (GNUNET_OK != + parse_reserve_history (history, + &wsh->reserve_pub, + balance.currency, + &balance_from_history, + len, + rhistory)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + + if (0 != + TALER_amount_cmp (&balance_from_history, + &balance)) + { + /* exchange cannot add up balances!? */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* Compute how much we expected to charge to the reserve */ + if (GNUNET_OK != + TALER_amount_add (&requested_amount, + &wsh->pk->value, + &wsh->pk->fee_withdraw)) + { + /* Overflow here? Very strange, our CPU must be fried... */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + /* Check that funds were really insufficient */ + if (0 >= TALER_amount_cmp (&requested_amount, + &balance)) + { + /* Requested amount is smaller or equal to reported balance, + so this should not have failed. */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /reserve/withdraw request. + * + * @param cls the `struct TALER_EXCHANGE_ReserveWithdrawHandle` + * @param eh curl handle of the request that finished + */ +static void +handle_reserve_withdraw_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh = cls; + long response_code; + json_t *json; + + wsh->job = NULL; + json = MAC_download_get_result (&wsh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + if (GNUNET_OK != + reserve_withdraw_ok (wsh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_PAYMENT_REQUIRED: + /* The exchange says that the reserve has insufficient funds; + check the signatures in the history... */ + if (GNUNET_OK != + reserve_withdraw_payment_required (wsh, + json)) + { + GNUNET_break_op (0); + response_code = 0; + } + break; + case MHD_HTTP_UNAUTHORIZED: + GNUNET_break (0); + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, the exchange basically just says + that it doesn't know this reserve. Can happen if we + query before the wire transfer went through. + We should simply pass the JSON reply to the application. */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != wsh->cb) + wsh->cb (wsh->cb_cls, + response_code, + NULL, + json); + json_decref (json); + TALER_EXCHANGE_reserve_withdraw_cancel (wsh); +} + + +/** + * Withdraw a coin from the exchange using a /reserve/withdraw request. Note + * that to ensure that no money is lost in case of hardware failures, + * the caller must have committed (most of) the arguments to disk + * before calling, and be ready to repeat the request with the same + * arguments in case of failures. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param pk kind of coin to create + * @param reserve_priv private key of the reserve to withdraw from + * @param coin_priv where to store the coin's private key, + * caller must have committed this value to disk before the call (with @a pk) + * @param blinding_key where to store the coin's blinding key + * caller must have committed this value to disk before the call (with @a pk) + * @param res_cb the callback to call when the final result for this request is available + * @param res_cb_cls closure for the above callback + * @return #GNUNET_OK on success, #GNUNET_SYSERR + * if the inputs are invalid (i.e. denomination key not with this exchange). + * In this case, the callback is not called. + */ +struct TALER_EXCHANGE_ReserveWithdrawHandle * +TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_EXCHANGE_DenomPublicKey *pk, + const struct TALER_ReservePrivateKeyP *reserve_priv, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + const struct TALER_DenominationBlindingKey *blinding_key, + TALER_EXCHANGE_ReserveWithdrawResultCallback res_cb, + void *res_cb_cls) +{ + struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; + struct TALER_WithdrawRequestPS req; + struct TALER_ReserveSignatureP reserve_sig; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_EXCHANGE_Context *ctx; + struct TALER_Amount amount_with_fee; + char *coin_ev; + size_t coin_ev_size; + json_t *withdraw_obj; + CURL *eh; + + wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveWithdrawHandle); + wsh->exchange = exchange; + wsh->cb = res_cb; + wsh->cb_cls = res_cb_cls; + wsh->pk = pk; + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), + &wsh->c_hash); + coin_ev_size = GNUNET_CRYPTO_rsa_blind (&wsh->c_hash, + blinding_key->rsa_blinding_key, + pk->key.rsa_public_key, + &coin_ev); + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, + &wsh->reserve_pub.eddsa_pub); + req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); + req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); + req.reserve_pub = wsh->reserve_pub; + if (GNUNET_OK != + TALER_amount_add (&amount_with_fee, + &pk->fee_withdraw, + &pk->value)) + { + /* exchange gave us denomination keys that overflow like this!? */ + GNUNET_break_op (0); + GNUNET_free (coin_ev); + GNUNET_free (wsh); + return NULL; + } + TALER_amount_hton (&req.amount_with_fee, + &amount_with_fee); + TALER_amount_hton (&req.withdraw_fee, + &pk->fee_withdraw); + GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key, + &req.h_denomination_pub); + GNUNET_CRYPTO_hash (coin_ev, + coin_ev_size, + &req.h_coin_envelope); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &req.purpose, + &reserve_sig.eddsa_signature)); + withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */ + " s:o, s:o}",/* reserve_pub and reserve_sig */ + "denom_pub", TALER_json_from_rsa_public_key (pk->key.rsa_public_key), + "coin_ev", TALER_json_from_data (coin_ev, + coin_ev_size), + "reserve_pub", TALER_json_from_data (&wsh->reserve_pub, + sizeof (struct TALER_ReservePublicKeyP)), + "reserve_sig", TALER_json_from_data (&reserve_sig, + sizeof (reserve_sig))); + GNUNET_free (coin_ev); + + wsh->blinding_key = blinding_key; + wsh->url = MAH_path_to_url (exchange, "/reserve/withdraw"); + + eh = curl_easy_init (); + GNUNET_assert (NULL != (wsh->json_enc = + json_dumps (withdraw_obj, + JSON_COMPACT))); + json_decref (withdraw_obj); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + wsh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + wsh->json_enc)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (wsh->json_enc))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &wsh->db)); + ctx = MAH_handle_to_context (exchange); + wsh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_reserve_withdraw_finished, + wsh); + return wsh; +} + + +/** + * Cancel a withdraw status request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param sign the withdraw sign request handle + */ +void +TALER_EXCHANGE_reserve_withdraw_cancel (struct TALER_EXCHANGE_ReserveWithdrawHandle *sign) +{ + if (NULL != sign->job) + { + MAC_job_cancel (sign->job); + sign->job = NULL; + } + GNUNET_free_non_null (sign->db.buf); + GNUNET_free (sign->url); + GNUNET_free (sign->json_enc); + GNUNET_free (sign); +} + + +/* end of exchange_api_reserve.c */ diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c new file mode 100644 index 000000000..fd40230c7 --- /dev/null +++ b/src/exchange-lib/exchange_api_wire.c @@ -0,0 +1,620 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_wire.c + * @brief Implementation of the /wire request of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief A Wire Handle + */ +struct TALER_EXCHANGE_WireHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_WireResultCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + + /** + * Set to the "methods" JSON array returned by the + * /wire request. + */ + json_t *methods; + + /** + * Current iteration offset in the @e methods array. + */ + unsigned int methods_off; + +}; + + +/** + * Verify that the signature on the "200 OK" response + * for /wire/sepa from the exchange is valid. + * + * @param wh wire handle + * @param json json reply with the signature + * @return #GNUNET_SYSERR if @a json is invalid, + * #GNUNET_NO if the method is unknown, + * #GNUNET_OK if the json is valid + */ +static int +verify_wire_sepa_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh, + json_t *json) +{ + struct TALER_MasterSignatureP exchange_sig; + struct TALER_MasterWireSepaDetailsPS mp; + const char *receiver_name; + const char *iban; + const char *bic; + const struct TALER_EXCHANGE_Keys *key_state; + struct GNUNET_HashContext *hc; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("sig", &exchange_sig), + MAJ_spec_string ("receiver_name", &receiver_name), + MAJ_spec_string ("iban", &iban), + MAJ_spec_string ("bic", &bic), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + key_state = TALER_EXCHANGE_get_keys (wh->exchange); + mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); + mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS)); + hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + receiver_name, + strlen (receiver_name) + 1); + GNUNET_CRYPTO_hash_context_read (hc, + iban, + strlen (iban) + 1); + GNUNET_CRYPTO_hash_context_read (hc, + bic, + strlen (bic) + 1); + GNUNET_CRYPTO_hash_context_finish (hc, + &mp.h_sepa_details); + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS, + &mp.purpose, + &exchange_sig.eddsa_signature, + &key_state->master_pub.eddsa_pub)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return GNUNET_SYSERR; + } + MAJ_parse_free (spec); + return GNUNET_OK; +} + + +/** + * Verify that the signature on the "200 OK" response + * for /wire/METHOD from the exchange is valid. + * + * @param wh wire handle with key material + * @param method method to verify the reply for + * @param json json reply with the signature + * @return #GNUNET_SYSERR if @a json is invalid, + * #GNUNET_NO if the method is unknown, + * #GNUNET_OK if the json is valid + */ +static int +verify_wire_method_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh, + const char *method, + json_t *json) +{ + struct + { + /** + * Name fo the method. + */ + const char *method; + + /** + * Handler to invoke to verify signature. + * + * @param wh wire handle with key material + * @param json json reply with signature to verify + */ + int (*handler)(const struct TALER_EXCHANGE_WireHandle *wh, + json_t *json); + } handlers[] = { + { "sepa", &verify_wire_sepa_signature_ok }, + { NULL, NULL } + }; + unsigned int i; + + for (i=0;NULL != handlers[i].method; i++) + if (0 == strcasecmp (handlers[i].method, + method)) + return handlers[i].handler (wh, + json); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Wire transfer method `%s' not supported\n", + method); + return GNUNET_NO; +} + + +/** + * Perform the next /wire/method request or signal + * the end of the iteration. + * + * @param wh the wire handle + * @return a handle for this request + */ +static void +request_wire_method (struct TALER_EXCHANGE_WireHandle *wh); + + +/** + * Function called when we're done processing the + * HTTP /wire/METHOD request. + * + * @param cls the `struct TALER_EXCHANGE_WireHandle` + * @param eh the curl request handle + */ +static void +handle_wire_method_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_WireHandle *wh = cls; + long response_code; + json_t *json; + + wh->job = NULL; + json = MAC_download_get_result (&wh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + const char *method; + + method = json_string_value (json_array_get (wh->methods, + wh->methods_off - 1)); + if (GNUNET_OK != + verify_wire_method_signature_ok (wh, + method, + json)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + break; + } + case MHD_HTTP_FOUND: + /* /wire/test returns a 302 redirect, we should just give + this information back to the callback below */ + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (0 == response_code) + { + /* signal end of iteration */ + wh->cb (wh->cb_cls, + 0, + NULL, + NULL); + json_decref (json); + TALER_EXCHANGE_wire_cancel (wh); + return; + } + /* pass on successful reply */ + wh->cb (wh->cb_cls, + response_code, + json_string_value (json_array_get (wh->methods, + wh->methods_off-1)), + json); + /* trigger request for the next /wire/method */ + request_wire_method (wh); +} + + +/** + * Perform the next /wire/method request or signal + * the end of the iteration. + * + * @param wh the wire handle + * @return a handle for this request + */ +static void +request_wire_method (struct TALER_EXCHANGE_WireHandle *wh) +{ + struct TALER_EXCHANGE_Context *ctx; + CURL *eh; + char *path; + + if (json_array_size (wh->methods) <= wh->methods_off) + { + /* we are done, signal end of iteration */ + wh->cb (wh->cb_cls, + 0, + NULL, + NULL); + TALER_EXCHANGE_wire_cancel (wh); + return; + } + GNUNET_free_non_null (wh->db.buf); + wh->db.buf = NULL; + wh->db.buf_size = 0; + wh->db.eno = 0; + GNUNET_free_non_null (wh->url); + GNUNET_asprintf (&path, + "/wire/%s", + json_string_value (json_array_get (wh->methods, + wh->methods_off++))); + wh->url = MAH_path_to_url (wh->exchange, + path); + GNUNET_free (path); + + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + wh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &wh->db)); + /* The default is 'disabled', but let's be sure */ + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_FOLLOWLOCATION, + (long) 0)); + ctx = MAH_handle_to_context (wh->exchange); + wh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_wire_method_finished, + wh); + TALER_EXCHANGE_perform (ctx); +} + + +/** + * Verify that the signature on the "200 OK" response + * for /wire from the exchange is valid. + * + * @param wh wire handle + * @param json json reply with the signature + * @return NULL if @a json is invalid, otherwise the + * "methods" array (with an RC of 1) + */ +static json_t * +verify_wire_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh, + json_t *json) +{ + struct TALER_ExchangeSignatureP exchange_sig; + struct TALER_ExchangePublicKeyP exchange_pub; + struct TALER_ExchangeWireSupportMethodsPS mp; + json_t *methods; + const struct TALER_EXCHANGE_Keys *key_state; + struct GNUNET_HashContext *hc; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("sig", &exchange_sig), + MAJ_spec_fixed_auto ("pub", &exchange_pub), + MAJ_spec_json ("methods", &methods), + MAJ_spec_end + }; + unsigned int i; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + return NULL; + } + if (! json_is_array (methods)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return NULL; + } + + key_state = TALER_EXCHANGE_get_keys (wh->exchange); + if (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_state, + &exchange_pub)) + { + GNUNET_break_op (0); + return NULL; + } + hc = GNUNET_CRYPTO_hash_context_start (); + for (i=0;i<json_array_size (methods);i++) + { + const json_t *element = json_array_get (methods, i); + const char *method; + + if (! json_is_string (element)) + { + GNUNET_CRYPTO_hash_context_abort (hc); + GNUNET_break_op (0); + MAJ_parse_free (spec); + return NULL; + } + method = json_string_value (element); + GNUNET_CRYPTO_hash_context_read (hc, + method, + strlen (method) + 1); + } + mp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES); + mp.purpose.size = htonl (sizeof (struct TALER_ExchangeWireSupportMethodsPS)); + GNUNET_CRYPTO_hash_context_finish (hc, + &mp.h_wire_types); + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES, + &mp.purpose, + &exchange_sig.eddsa_signature, + &exchange_pub.eddsa_pub)) + { + GNUNET_break_op (0); + MAJ_parse_free (spec); + return NULL; + } + return methods; +} + + +/** + * Function called when we're done processing the + * HTTP /wire request. + * + * @param cls the `struct TALER_EXCHANGE_WireHandle` + * @param eh the curl request handle + */ +static void +handle_wire_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_WireHandle *wh = cls; + long response_code; + json_t *json; + + wh->job = NULL; + json = MAC_download_get_result (&wh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + json_t *methods; + + if (NULL == + (methods = verify_wire_signature_ok (wh, + json))) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + wh->methods = methods; + request_wire_method (wh); + return; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (0 != response_code) + { + /* pass on successful reply */ + wh->cb (wh->cb_cls, + response_code, + NULL, + json); + } + /* signal end of iteration */ + wh->cb (wh->cb_cls, + 0, + NULL, + NULL); + if (NULL != json) + json_decref (json); + TALER_EXCHANGE_wire_cancel (wh); +} + + +/** + * Obtain information about a exchange's wire instructions. + * A exchange may provide wire instructions for creating + * a reserve. The wire instructions also indicate + * which wire formats merchants may use with the exchange. + * This API is typically used by a wallet for wiring + * funds, and possibly by a merchant to determine + * supported wire formats. + * + * Note that while we return the (main) response verbatim to the + * caller for further processing, we do already verify that the + * response is well-formed (i.e. that signatures included in the + * response are all valid). If the exchange's reply is not well-formed, + * we return an HTTP status code of zero to @a cb. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param wire_cb the callback to call when a reply for this request is available + * @param wire_cb_cls closure for the above callback + * @return a handle for this request + */ +struct TALER_EXCHANGE_WireHandle * +TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange, + TALER_EXCHANGE_WireResultCallback wire_cb, + void *wire_cb_cls) +{ + struct TALER_EXCHANGE_WireHandle *wh; + struct TALER_EXCHANGE_Context *ctx; + CURL *eh; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + wh = GNUNET_new (struct TALER_EXCHANGE_WireHandle); + wh->exchange = exchange; + wh->cb = wire_cb; + wh->cb_cls = wire_cb_cls; + wh->url = MAH_path_to_url (exchange, "/wire"); + + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + wh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &wh->db)); + ctx = MAH_handle_to_context (exchange); + wh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_wire_finished, + wh); + return wh; +} + + +/** + * Cancel a wire information request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param wh the wire information request handle + */ +void +TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh) +{ + if (NULL != wh->job) + { + MAC_job_cancel (wh->job); + wh->job = NULL; + } + if (NULL != wh->methods) + { + json_decref (wh->methods); + wh->methods = NULL; + } + GNUNET_free_non_null (wh->db.buf); + GNUNET_free (wh->url); + GNUNET_free (wh); +} + + +/* end of exchange_api_wire.c */ diff --git a/src/exchange-lib/exchange_api_wire_deposits.c b/src/exchange-lib/exchange_api_wire_deposits.c new file mode 100644 index 000000000..281ae2097 --- /dev/null +++ b/src/exchange-lib/exchange_api_wire_deposits.c @@ -0,0 +1,284 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/exchange_api_wire_deposits.c + * @brief Implementation of the /wire/deposits request of the exchange's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_json.h" +#include "exchange_api_context.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" + + +/** + * @brief A /wire/deposits Handle + */ +struct TALER_EXCHANGE_WireDepositsHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct MAC_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_WireDepositsCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Download buffer + */ + struct MAC_DownloadBuffer db; + +}; + + +/** + * Function called when we're done processing the + * HTTP /wire/deposits request. + * + * @param cls the `struct TALER_EXCHANGE_WireDepositsHandle` + * @param eh the curl request handle + */ +static void +handle_wire_deposits_finished (void *cls, + CURL *eh) +{ + struct TALER_EXCHANGE_WireDepositsHandle *wdh = cls; + long response_code; + json_t *json; + + wdh->job = NULL; + json = MAC_download_get_result (&wdh->db, + eh, + &response_code); + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + json_t *details_j; + struct GNUNET_HashCode h_wire; + struct TALER_Amount total_amount; + struct TALER_MerchantPublicKeyP merchant_pub; + unsigned int num_details; + struct MAJ_Specification spec[] = { + MAJ_spec_fixed_auto ("H_wire", &h_wire), + MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub), + MAJ_spec_amount ("total_amount", &total_amount), + MAJ_spec_json ("details", &details_j), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (json, + spec)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + num_details = json_array_size (details_j); + { + struct TALER_WireDepositDetails details[num_details]; + unsigned int i; + + for (i=0;i<num_details;i++) + { + struct TALER_WireDepositDetails *detail = &details[i]; + struct json_t *detail_j = json_array_get (details_j, i); + struct MAJ_Specification spec_detail[] = { + MAJ_spec_fixed_auto ("H_contract", &detail->h_contract), + MAJ_spec_amount ("deposit_value", &detail->coin_value), + MAJ_spec_amount ("deposit_fee", &detail->coin_fee), + MAJ_spec_uint64 ("transaction_id", &detail->transaction_id), + MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub), + MAJ_spec_end + }; + + if (GNUNET_OK != + MAJ_parse_json (detail_j, + spec_detail)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + } + if (0 == response_code) + break; + wdh->cb (wdh->cb_cls, + response_code, + json, + &h_wire, + &total_amount, + num_details, + details); + json_decref (json); + TALER_EXCHANGE_wire_deposits_cancel (wdh); + return; + } + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_UNAUTHORIZED: + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Exchange does not know about transaction; + we should pass the reply to the application */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + response_code); + GNUNET_break (0); + response_code = 0; + break; + } + wdh->cb (wdh->cb_cls, + response_code, + json, + NULL, NULL, 0, NULL); + json_decref (json); + TALER_EXCHANGE_wire_deposits_cancel (wdh); +} + + +/** + * Query the exchange about which transactions were combined + * to create a wire transfer. + * + * @param exchange exchange to query + * @param wtid raw wire transfer identifier to get information about + * @param cb callback to call + * @param cb_cls closure for @a cb + * @return handle to cancel operation + */ +struct TALER_EXCHANGE_WireDepositsHandle * +TALER_EXCHANGE_wire_deposits (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_WireTransferIdentifierRawP *wtid, + TALER_EXCHANGE_WireDepositsCallback cb, + void *cb_cls) +{ + struct TALER_EXCHANGE_WireDepositsHandle *wdh; + struct TALER_EXCHANGE_Context *ctx; + char *buf; + char *path; + CURL *eh; + + if (GNUNET_YES != + MAH_handle_is_ready (exchange)) + { + GNUNET_break (0); + return NULL; + } + + wdh = GNUNET_new (struct TALER_EXCHANGE_WireDepositsHandle); + wdh->exchange = exchange; + wdh->cb = cb; + wdh->cb_cls = cb_cls; + + buf = GNUNET_STRINGS_data_to_string_alloc (wtid, + sizeof (struct TALER_WireTransferIdentifierRawP)); + GNUNET_asprintf (&path, + "/wire/deposits?wtid=%s", + buf); + wdh->url = MAH_path_to_url (wdh->exchange, + path); + GNUNET_free (buf); + GNUNET_free (path); + + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + wdh->url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEFUNCTION, + &MAC_download_cb)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_WRITEDATA, + &wdh->db)); + ctx = MAH_handle_to_context (exchange); + wdh->job = MAC_job_add (ctx, + eh, + GNUNET_YES, + &handle_wire_deposits_finished, + wdh); + return wdh; +} + + +/** + * Cancel wire deposits request. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param wdh the wire deposits request handle + */ +void +TALER_EXCHANGE_wire_deposits_cancel (struct TALER_EXCHANGE_WireDepositsHandle *wdh) +{ + if (NULL != wdh->job) + { + MAC_job_cancel (wdh->job); + wdh->job = NULL; + } + GNUNET_free_non_null (wdh->db.buf); + GNUNET_free (wdh->url); + GNUNET_free (wdh); +} + + +/* end of exchange_api_wire_deposits.c */ diff --git a/src/exchange-lib/test-exchange-home/config/mint-common.conf b/src/exchange-lib/test-exchange-home/config/mint-common.conf new file mode 100644 index 000000000..01dd6c896 --- /dev/null +++ b/src/exchange-lib/test-exchange-home/config/mint-common.conf @@ -0,0 +1,30 @@ +[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" + +[exchange-wire-sepa] +SEPA_RESPONSE_FILE = "test-exchange-home/sepa.json" + +[exchange-wire-test] +REDIRECT_URL = "http://www.taler.net/" diff --git a/src/exchange-lib/test-exchange-home/config/mint-keyup.conf b/src/exchange-lib/test-exchange-home/config/mint-keyup.conf new file mode 100644 index 000000000..4a80da7e9 --- /dev/null +++ b/src/exchange-lib/test-exchange-home/config/mint-keyup.conf @@ -0,0 +1,86 @@ +[exchange_keys] + +# how long is one signkey valid? +signkey_duration = 4 weeks + +# how long are the signatures with the signkey valid? +legal_duration = 2 years + +# how long do we generate denomination and signing keys +# ahead of time? +lookahead_sign = 32 weeks 1 day + +# how long do we provide to clients denomination and signing keys +# ahead of time? +lookahead_provide = 4 weeks 1 day + + +# Coin definitions are detected because the section +# name begins with "coin_". The rest of the +# name is free, but of course following the convention +# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense. +[coin_eur_ct_1] +value = EUR:0.01 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.00 +fee_deposit = EUR:0.00 +fee_refresh = EUR:0.01 +rsa_keysize = 1024 + +[coin_eur_ct_10] +value = EUR:0.10 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +rsa_keysize = 1024 + +[coin_eur_1] +value = EUR:1 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +rsa_keysize = 1024 + +[coin_eur_5] +value = EUR:5 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +rsa_keysize = 1024 + +[coin_eur_10] +value = EUR:10 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +rsa_keysize = 1024 + +[coin_eur_1000] +value = EUR:1000 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +rsa_keysize = 2048 diff --git a/src/mint-lib/test-mint-home/master.priv b/src/exchange-lib/test-exchange-home/master.priv index 394926938..394926938 100644 --- a/src/mint-lib/test-mint-home/master.priv +++ b/src/exchange-lib/test-exchange-home/master.priv diff --git a/src/mint-lib/test-mint-home/sepa.json b/src/exchange-lib/test-exchange-home/sepa.json index 36d12f661..36d12f661 100644 --- a/src/mint-lib/test-mint-home/sepa.json +++ b/src/exchange-lib/test-exchange-home/sepa.json diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c new file mode 100644 index 000000000..a6da380df --- /dev/null +++ b/src/exchange-lib/test_exchange_api.c @@ -0,0 +1,2599 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange/test_exchange_api.c + * @brief testcase to test exchange's HTTP API interface + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> + +/** + * Is the configuration file is set to include wire format 'test'? + */ +#define WIRE_TEST 1 + +/** + * Is the configuration file is set to include wire format 'sepa'? + */ +#define WIRE_SEPA 1 + +/** + * Main execution context for the main loop. + */ +static struct TALER_EXCHANGE_Context *ctx; + +/** + * Handle to access the exchange. + */ +static struct TALER_EXCHANGE_Handle *exchange; + +/** + * Task run on shutdown. + */ +static struct GNUNET_SCHEDULER_Task *shutdown_task; + +/** + * Task that runs the main event loop. + */ +static struct GNUNET_SCHEDULER_Task *ctx_task; + +/** + * Result of the testcases, #GNUNET_OK on success + */ +static int result; + + +/** + * Opcodes for the interpreter. + */ +enum OpCode +{ + /** + * Termination code, stops the interpreter loop (with success). + */ + OC_END = 0, + + /** + * Add funds to a reserve by (faking) incoming wire transfer. + */ + OC_ADMIN_ADD_INCOMING, + + /** + * Check status of a reserve. + */ + OC_WITHDRAW_STATUS, + + /** + * Withdraw a coin from a reserve. + */ + OC_WITHDRAW_SIGN, + + /** + * Deposit a coin (pay with it). + */ + OC_DEPOSIT, + + /** + * Melt a (set of) coins. + */ + OC_REFRESH_MELT, + + /** + * Complete melting session by withdrawing melted coins. + */ + OC_REFRESH_REVEAL, + + /** + * Verify exchange's /refresh/link by linking original private key to + * results from #OC_REFRESH_REVEAL step. + */ + OC_REFRESH_LINK, + + /** + * Verify the exchange's /wire-method. + */ + OC_WIRE, + + /** + * Verify exchange's /wire/deposits method. + */ + OC_WIRE_DEPOSITS, + + /** + * Verify exchange's /deposit/wtid method. + */ + OC_DEPOSIT_WTID + +}; + + +/** + * Structure specifying details about a coin to be melted. + * Used in a NULL-terminated array as part of command + * specification. + */ +struct MeltDetails +{ + + /** + * Amount to melt (including fee). + */ + const char *amount; + + /** + * Reference to reserve_withdraw operations for coin to + * be used for the /refresh/melt operation. + */ + const char *coin_ref; + +}; + + +/** + * Information about a fresh coin generated by the refresh operation. + */ +struct FreshCoin +{ + + /** + * If @e amount is NULL, this specifies the denomination key to + * use. Otherwise, this will be set (by the interpreter) to the + * denomination PK matching @e amount. + */ + const struct TALER_EXCHANGE_DenomPublicKey *pk; + + /** + * Set (by the interpreter) to the exchange's signature over the + * coin's public key. + */ + struct TALER_DenominationSignature sig; + + /** + * Set (by the interpreter) to the coin's private key. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + +}; + + +/** + * Details for a exchange operation to execute. + */ +struct Command +{ + /** + * Opcode of the command. + */ + enum OpCode oc; + + /** + * Label for the command, can be NULL. + */ + const char *label; + + /** + * Which response code do we expect for this command? + */ + unsigned int expected_response_code; + + /** + * Details about the command. + */ + union + { + + /** + * Information for a #OC_ADMIN_ADD_INCOMING command. + */ + struct + { + + /** + * Label to another admin_add_incoming command if we + * should deposit into an existing reserve, NULL if + * a fresh reserve should be created. + */ + const char *reserve_reference; + + /** + * String describing the amount to add to the reserve. + */ + const char *amount; + + /** + * Wire details (JSON). + */ + const char *wire; + + /** + * Set (by the interpreter) to the reserve's private key + * we used to fill the reserve. + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + /** + * Set to the API's handle during the operation. + */ + struct TALER_EXCHANGE_AdminAddIncomingHandle *aih; + + } admin_add_incoming; + + /** + * Information for a #OC_WITHDRAW_STATUS command. + */ + struct + { + + /** + * Label to the #OC_ADMIN_ADD_INCOMING command which + * created the reserve. + */ + const char *reserve_reference; + + /** + * Set to the API's handle during the operation. + */ + struct TALER_EXCHANGE_ReserveStatusHandle *wsh; + + /** + * Expected reserve balance. + */ + const char *expected_balance; + + } reserve_status; + + /** + * Information for a #OC_WITHDRAW_SIGN command. + */ + struct + { + + /** + * Which reserve should we withdraw from? + */ + const char *reserve_reference; + + /** + * String describing the denomination value we should withdraw. + * A corresponding denomination key must exist in the exchange's + * offerings. Can be NULL if @e pk is set instead. + */ + const char *amount; + + /** + * If @e amount is NULL, this specifies the denomination key to + * use. Otherwise, this will be set (by the interpreter) to the + * denomination PK matching @e amount. + */ + const struct TALER_EXCHANGE_DenomPublicKey *pk; + + /** + * Set (by the interpreter) to the exchange's signature over the + * coin's public key. + */ + struct TALER_DenominationSignature sig; + + /** + * Set (by the interpreter) to the coin's private key. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * Blinding key used for the operation. + */ + struct TALER_DenominationBlindingKey blinding_key; + + /** + * Withdraw handle (while operation is running). + */ + struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; + + } reserve_withdraw; + + /** + * Information for a #OC_DEPOSIT command. + */ + struct + { + + /** + * Amount to deposit. + */ + const char *amount; + + /** + * Reference to a reserve_withdraw operation for a coin to + * be used for the /deposit operation. + */ + const char *coin_ref; + + /** + * If this @e coin_ref refers to an operation that generated + * an array of coins, this value determines which coin to use. + */ + unsigned int coin_idx; + + /** + * JSON string describing the merchant's "wire details". + */ + const char *wire_details; + + /** + * JSON string describing the contract between the two parties. + */ + const char *contract; + + /** + * Transaction ID to use. + */ + uint64_t transaction_id; + + /** + * Relative time (to add to 'now') to compute the refund deadline. + * Zero for no refunds. + */ + struct GNUNET_TIME_Relative refund_deadline; + + /** + * Set (by the interpreter) to a fresh private key of the merchant, + * if @e refund_deadline is non-zero. + */ + struct TALER_MerchantPrivateKeyP merchant_priv; + + /** + * Deposit handle while operation is running. + */ + struct TALER_EXCHANGE_DepositHandle *dh; + + } deposit; + + /** + * Information for a #OC_REFRESH_MELT command. + */ + struct + { + + /** + * Information about coins to be melted. + */ + struct MeltDetails *melted_coins; + + /** + * Denominations of the fresh coins to withdraw. + */ + const char **fresh_amounts; + + /** + * Array of the public keys corresponding to + * the @e fresh_amounts, set by the interpreter. + */ + const struct TALER_EXCHANGE_DenomPublicKey **fresh_pks; + + /** + * Melt handle while operation is running. + */ + struct TALER_EXCHANGE_RefreshMeltHandle *rmh; + + /** + * Data used in the refresh operation, set by the interpreter. + */ + char *refresh_data; + + /** + * Number of bytes in @e refresh_data, set by the interpreter. + */ + size_t refresh_data_length; + + /** + * Set by the interpreter (upon completion) to the noreveal + * index selected by the exchange. + */ + uint16_t noreveal_index; + + } refresh_melt; + + /** + * Information for a #OC_REFRESH_REVEAL command. + */ + struct + { + + /** + * Melt operation this is the matching reveal for. + */ + const char *melt_ref; + + /** + * Reveal handle while operation is running. + */ + struct TALER_EXCHANGE_RefreshRevealHandle *rrh; + + /** + * Number of fresh coins withdrawn, set by the interpreter. + * Length of the @e fresh_coins array. + */ + unsigned int num_fresh_coins; + + /** + * Information about coins withdrawn, set by the interpreter. + */ + struct FreshCoin *fresh_coins; + + } refresh_reveal; + + /** + * Information for a #OC_REFRESH_LINK command. + */ + struct + { + + /** + * Reveal operation this is the matching link for. + */ + const char *reveal_ref; + + /** + * Link handle while operation is running. + */ + struct TALER_EXCHANGE_RefreshLinkHandle *rlh; + + /** + * Which of the melted coins should be used for the linkage? + */ + unsigned int coin_idx; + + } refresh_link; + + /** + * Information for the /wire command. + */ + struct { + + /** + * Handle to the wire request. + */ + struct TALER_EXCHANGE_WireHandle *wh; + + /** + * Format we expect to see, others will be *ignored*. + */ + const char *format; + + } wire; + + /** + * Information for the /wire/deposits's command. + */ + struct { + + /** + * Handle to the wire deposits request. + */ + struct TALER_EXCHANGE_WireDepositsHandle *wdh; + + /** + * Reference to a /deposit/wtid command. If set, we use the + * WTID from that command. + */ + const char *wtid_ref; + + /** + * WTID to use (used if @e wtid_ref is NULL). + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /* TODO: may want to add list of deposits we expected + to see aggregated here in the future. */ + + } wire_deposits; + + /** + * Information for the /deposit/wtid command. + */ + struct { + + /** + * Handle to the deposit wtid request. + */ + struct TALER_EXCHANGE_DepositWtidHandle *dwh; + + /** + * Which /deposit operation should we obtain WTID data for? + */ + const char *deposit_ref; + + /** + * What is the expected total amount? Only used if + * @e expected_response_code was #MHD_HTTP_OK. + */ + struct TALER_Amount total_amount_expected; + + /** + * Wire transfer identifier, set if #MHD_HTTP_OK was the response code. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + } deposit_wtid; + + } details; + +}; + + +/** + * State of the interpreter loop. + */ +struct InterpreterState +{ + /** + * Keys from the exchange. + */ + const struct TALER_EXCHANGE_Keys *keys; + + /** + * Commands the interpreter will run. + */ + struct Command *commands; + + /** + * Interpreter task (if one is scheduled). + */ + struct GNUNET_SCHEDULER_Task *task; + + /** + * Instruction pointer. Tells #interpreter_run() which + * instruction to run next. + */ + unsigned int ip; + +}; + + +/** + * Task that runs the context's event loop with the GNUnet scheduler. + * + * @param cls unused + * @param tc scheduler context (unused) + */ +static void +context_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Run the context task, the working set has changed. + */ +static void +trigger_context_task () +{ + GNUNET_SCHEDULER_cancel (ctx_task); + ctx_task = GNUNET_SCHEDULER_add_now (&context_task, + NULL); +} + + +/** + * The testcase failed, return with an error code. + * + * @param is interpreter state to clean up + */ +static void +fail (struct InterpreterState *is) +{ + result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Find a command by label. + * + * @param is interpreter state to search + * @param label label to look for + * @return NULL if command was not found + */ +static const struct Command * +find_command (const struct InterpreterState *is, + const char *label) +{ + unsigned int i; + const struct Command *cmd; + + if (NULL == label) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Attempt to lookup command for empty label\n"); + return NULL; + } + for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++) + if ( (NULL != cmd->label) && + (0 == strcmp (cmd->label, + label)) ) + return cmd; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command not found: %s\n", + label); + return NULL; +} + + +/** + * Run the main interpreter loop that performs exchange operations. + * + * @param cls contains the `struct InterpreterState` + * @param tc scheduler context + */ +static void +interpreter_run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called upon completion of our /admin/add/incoming request. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param full_response full response from the exchange (for logging, in case of errors) + */ +static void +add_incoming_cb (void *cls, + unsigned int http_status, + json_t *full_response) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + cmd->details.admin_add_incoming.aih = NULL; + if (MHD_HTTP_OK != http_status) + { + GNUNET_break (0); + fail (is); + return; + } + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Check if the given historic event @a h corresponds to the given + * command @a cmd. + * + * @param h event in history + * @param cmd an #OC_ADMIN_ADD_INCOMING command + * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not + */ +static int +compare_admin_add_incoming_history (const struct TALER_EXCHANGE_ReserveHistory *h, + const struct Command *cmd) +{ + struct TALER_Amount amount; + + if (TALER_EXCHANGE_RTT_DEPOSIT != h->type) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (cmd->details.admin_add_incoming.amount, + &amount)); + if (0 != TALER_amount_cmp (&amount, + &h->amount)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Check if the given historic event @a h corresponds to the given + * command @a cmd. + * + * @param h event in history + * @param cmd an #OC_WITHDRAW_SIGN command + * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not + */ +static int +compare_reserve_withdraw_history (const struct TALER_EXCHANGE_ReserveHistory *h, + const struct Command *cmd) +{ + struct TALER_Amount amount; + struct TALER_Amount amount_with_fee; + + if (TALER_EXCHANGE_RTT_WITHDRAWAL != h->type) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (cmd->details.reserve_withdraw.amount, + &amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&amount_with_fee, + &amount, + &cmd->details.reserve_withdraw.pk->fee_withdraw)); + if (0 != TALER_amount_cmp (&amount_with_fee, + &h->amount)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Function called with the result of a /reserve/status request. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param[in] json original response in JSON format (useful only for diagnostics) + * @param balance current balance in the reserve, NULL on error + * @param history_length number of entries in the transaction history, 0 on error + * @param history detailed transaction history, NULL on error + */ +static void +reserve_status_cb (void *cls, + unsigned int http_status, + json_t *json, + const struct TALER_Amount *balance, + unsigned int history_length, + const struct TALER_EXCHANGE_ReserveHistory *history) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + struct Command *rel; + unsigned int i; + unsigned int j; + struct TALER_Amount amount; + + cmd->details.reserve_status.wsh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + GNUNET_break (0); + json_dumpf (json, stderr, 0); + fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + /* FIXME: note that history events may come in a different + order than the commands. However, for now this works... */ + j = 0; + for (i=0;i<is->ip;i++) + { + switch ((rel = &is->commands[i])->oc) + { + case OC_ADMIN_ADD_INCOMING: + if ( ( (NULL != rel->label) && + (0 == strcmp (cmd->details.reserve_status.reserve_reference, + rel->label) ) ) || + ( (NULL != rel->details.admin_add_incoming.reserve_reference) && + (0 == strcmp (cmd->details.reserve_status.reserve_reference, + rel->details.admin_add_incoming.reserve_reference) ) ) ) + { + if (GNUNET_OK != + compare_admin_add_incoming_history (&history[j], + rel)) + { + GNUNET_break (0); + fail (is); + return; + } + j++; + } + break; + case OC_WITHDRAW_SIGN: + if (0 == strcmp (cmd->details.reserve_status.reserve_reference, + rel->details.reserve_withdraw.reserve_reference)) + { + if (GNUNET_OK != + compare_reserve_withdraw_history (&history[j], + rel)) + { + GNUNET_break (0); + fail (is); + return; + } + j++; + } + break; + default: + /* unreleated, just skip */ + break; + } + } + if (j != history_length) + { + GNUNET_break (0); + fail (is); + return; + } + if (NULL != cmd->details.reserve_status.expected_balance) + { + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (cmd->details.reserve_status.expected_balance, + &amount)); + if (0 != TALER_amount_cmp (&amount, + balance)) + { + GNUNET_break (0); + fail (is); + return; + } + } + break; + default: + /* Unsupported status code (by test harness) */ + GNUNET_break (0); + break; + } + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called upon completion of our /reserve/withdraw request. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param sig signature over the coin, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +static void +reserve_withdraw_cb (void *cls, + unsigned int http_status, + const struct TALER_DenominationSignature *sig, + json_t *full_response) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + cmd->details.reserve_withdraw.wsh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (full_response, stderr, 0); + GNUNET_break (0); + fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + if (NULL == sig) + { + GNUNET_break (0); + fail (is); + return; + } + cmd->details.reserve_withdraw.sig.rsa_signature + = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); + break; + case MHD_HTTP_PAYMENT_REQUIRED: + /* nothing to check */ + break; + default: + /* Unsupported status code (by test harness) */ + GNUNET_break (0); + break; + } + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called with the result of a /deposit operation. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param obj the received JSON reply, should be kept as proof (and, in case of errors, + * be forwarded to the customer) + */ +static void +deposit_cb (void *cls, + unsigned int http_status, + json_t *obj) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + cmd->details.deposit.dh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (obj, stderr, 0); + fail (is); + return; + } + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called with the result of the /refresh/melt operation. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param noreveal_index choice by the exchange in the cut-and-choose protocol, + * UINT16_MAX on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +static void +melt_cb (void *cls, + unsigned int http_status, + uint16_t noreveal_index, + json_t *full_response) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + cmd->details.refresh_melt.rmh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (full_response, stderr, 0); + fail (is); + return; + } + cmd->details.refresh_melt.noreveal_index = noreveal_index; + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called with the result of the /refresh/reveal operation. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed + * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error + * @param sigs array of signature over @a num_coins coins, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +static void +reveal_cb (void *cls, + unsigned int http_status, + unsigned int num_coins, + const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_DenominationSignature *sigs, + json_t *full_response) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + const struct Command *ref; + unsigned int i; + + cmd->details.refresh_reveal.rrh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (full_response, stderr, 0); + fail (is); + return; + } + ref = find_command (is, + cmd->details.refresh_reveal.melt_ref); + cmd->details.refresh_reveal.num_fresh_coins = num_coins; + switch (http_status) + { + case MHD_HTTP_OK: + cmd->details.refresh_reveal.fresh_coins + = GNUNET_new_array (num_coins, + struct FreshCoin); + for (i=0;i<num_coins;i++) + { + struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i]; + + fc->pk = ref->details.refresh_melt.fresh_pks[i]; + fc->coin_priv = coin_privs[i]; + fc->sig.rsa_signature + = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature); + } + break; + default: + break; + } + + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called with the result of a /refresh/link operation. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed + * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error + * @param sigs array of signature over @a num_coins coins, NULL on error + * @param pubs array of public keys for the @a sigs, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +static void +link_cb (void *cls, + unsigned int http_status, + unsigned int num_coins, + const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_DenominationSignature *sigs, + const struct TALER_DenominationPublicKey *pubs, + json_t *full_response) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + const struct Command *ref; + unsigned int i; + unsigned int j; + unsigned int found; + + cmd->details.refresh_link.rlh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (full_response, stderr, 0); + fail (is); + return; + } + ref = find_command (is, + cmd->details.refresh_link.reveal_ref); + switch (http_status) + { + case MHD_HTTP_OK: + /* check that number of coins returned matches */ + if (num_coins != ref->details.refresh_reveal.num_fresh_coins) + { + GNUNET_break (0); + fail (is); + return; + } + /* check that the coins match */ + for (i=0;i<num_coins;i++) + for (j=i+1;j<num_coins;j++) + if (0 == memcmp (&coin_privs[i], + &coin_privs[j], + sizeof (struct TALER_CoinSpendPrivateKeyP))) + GNUNET_break (0); + /* Note: coins might be legitimately permutated in here... */ + found = 0; + for (i=0;i<num_coins;i++) + for (j=0;j<num_coins;j++) + { + const struct FreshCoin *fc; + + fc = &ref->details.refresh_reveal.fresh_coins[j]; + if ( (0 == memcmp (&coin_privs[i], + &fc->coin_priv, + sizeof (struct TALER_CoinSpendPrivateKeyP))) && + (0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature, + sigs[i].rsa_signature)) && + (0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key, + pubs[i].rsa_public_key)) ) + { + found++; + break; + } + } + if (found != num_coins) + { + fprintf (stderr, + "Only %u/%u coins match expectations\n", + found, + num_coins); + GNUNET_break (0); + fail (is); + return; + } + break; + default: + break; + } + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Find denomination key matching the given amount. + * + * @param keys array of keys to search + * @param amount coin value to look for + * @return NULL if no matching key was found + */ +static const struct TALER_EXCHANGE_DenomPublicKey * +find_pk (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_Amount *amount) +{ + unsigned int i; + struct GNUNET_TIME_Absolute now; + struct TALER_EXCHANGE_DenomPublicKey *pk; + char *str; + + now = GNUNET_TIME_absolute_get (); + for (i=0;i<keys->num_denom_keys;i++) + { + pk = &keys->denom_keys[i]; + if ( (0 == TALER_amount_cmp (amount, + &pk->value)) && + (now.abs_value_us >= pk->valid_from.abs_value_us) && + (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) ) + return pk; + } + /* do 2nd pass to check if expiration times are to blame for failure */ + str = TALER_amount_to_string (amount); + for (i=0;i<keys->num_denom_keys;i++) + { + pk = &keys->denom_keys[i]; + if ( (0 == TALER_amount_cmp (amount, + &pk->value)) && + ( (now.abs_value_us < pk->valid_from.abs_value_us) || + (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n", + str, + now.abs_value_us, + pk->valid_from.abs_value_us, + pk->withdraw_valid_until.abs_value_us); + GNUNET_free (str); + return NULL; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No denomination key for amount %s found\n", + str); + GNUNET_free (str); + return NULL; +} + + +/** + * Callbacks called with the result(s) of a + * wire format inquiry request to the exchange. + * + * The callback is invoked multiple times, once for each supported @a + * method. Finally, it is invoked one more time with cls/0/NULL/NULL + * to indicate the end of the iteration. If any request fails to + * generate a valid response from the exchange, @a http_status will also + * be zero and the iteration will also end. Thus, the iteration + * always ends with a final call with an @a http_status of 0. If the + * @a http_status is already 0 on the first call, then the response to + * the /wire request was invalid. Later, clients can tell the + * difference between @a http_status of 0 indicating a failed + * /wire/method request and a regular end of the iteration by @a + * method being non-NULL. If the exchange simply correctly asserts that + * it does not support any methods, @a method will be NULL but the @a + * http_status will be #MHD_HTTP_OK for the first call (followed by a + * cls/0/NULL/NULL call to signal the end of the iteration). + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param method wire format method supported, i.e. "test" or "sepa", or NULL + * if already the /wire request failed. + * @param obj the received JSON reply, if successful this should be the wire + * format details as provided by /wire/METHOD/, or NULL if the + * reply was not in JSON format (in this case, the client might + * want to do an HTTP request to /wire/METHOD/ with a browser to + * provide more information to the user about the @a method). + */ +static void +wire_cb (void *cls, + unsigned int http_status, + const char *method, + json_t *obj) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + if (0 == http_status) + { + /* 0 always signals the end of the iteration */ + cmd->details.wire.wh = NULL; + } + else if ( (NULL != method) && + (0 != strcasecmp (method, + cmd->details.wire.format)) ) + { + /* not the method we care about, skip */ + return; + } + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s/%s\n", + http_status, + cmd->label, + method); + json_dumpf (obj, stderr, 0); + fail (is); + return; + } + if (0 == http_status) + { + /* end of iteration, move to next command */ + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); + return; + } + /* For now, we only support to be called only once + with a "positive" result; so we switch to an + expected value of 0 for the 2nd iteration */ + cmd->expected_response_code = 0; +} + + +/** + * Function called with detailed wire transfer data, including all + * of the coin transactions that were combined into the wire transfer. + * + * @param cls closure + * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param json original json reply (may include signatures, those have then been + * validated already) + * @param wtid extracted wire transfer identifier, or NULL if the exchange could + * not provide any (set only if @a http_status is #MHD_HTTP_OK) + * @param total_amount total amount of the wire transfer, or NULL if the exchange could + * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) + * @param details_length length of the @a details array + * @param details array with details about the combined transactions + */ +static void +wire_deposits_cb (void *cls, + unsigned int http_status, + json_t *json, + const struct GNUNET_HashCode *h_wire, + const struct TALER_Amount *total_amount, + unsigned int details_length, + const struct TALER_WireDepositDetails *details) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + const struct Command *ref; + + cmd->details.wire_deposits.wdh = NULL; + ref = find_command (is, + cmd->details.wire_deposits.wtid_ref); + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (json, stderr, 0); + fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + if (0 != TALER_amount_cmp (total_amount, + &ref->details.deposit_wtid.total_amount_expected)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Total amount missmatch to command %s\n", + http_status, + cmd->label); + json_dumpf (json, stderr, 0); + fail (is); + return; + } + if (NULL != ref->details.deposit_wtid.deposit_ref) + { + const struct Command *dep; + struct GNUNET_HashCode hw; + + dep = find_command (is, + ref->details.deposit_wtid.deposit_ref); + GNUNET_CRYPTO_hash (dep->details.deposit.wire_details, + strlen (dep->details.deposit.wire_details), + &hw); + if (0 != memcmp (&hw, + h_wire, + sizeof (struct GNUNET_HashCode))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire hash missmatch to command %s\n", + cmd->label); + json_dumpf (json, stderr, 0); + fail (is); + return; + } + } + break; + default: + break; + } + + /* move to next command */ + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Function called with detailed wire transfer data. + * + * @param cls closure + * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param json original json reply (may include signatures, those have then been + * validated already) + * @param wtid wire transfer identifier used by the exchange, NULL if exchange did not + * yet execute the transaction + * @param execution_time actual or planned execution time for the wire transfer + * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL) + * @param total_amount total amount of the wire transfer, or NULL if the exchange could + * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) + */ +static void +deposit_wtid_cb (void *cls, + unsigned int http_status, + json_t *json, + const struct TALER_WireTransferIdentifierRawP *wtid, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_Amount *coin_contribution) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + + cmd->details.deposit_wtid.dwh = NULL; + if (cmd->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s\n", + http_status, + cmd->label); + json_dumpf (json, stderr, 0); + fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + cmd->details.deposit_wtid.wtid = *wtid; + break; + default: + break; + } + + /* move to next command */ + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Run the main interpreter loop that performs exchange operations. + * + * @param cls contains the `struct InterpreterState` + * @param tc scheduler context + */ +static void +interpreter_run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip]; + const struct Command *ref; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_Amount amount; + struct GNUNET_TIME_Absolute execution_date; + json_t *wire; + + is->task = NULL; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + fprintf (stderr, + "Test aborted by shutdown request\n"); + fail (is); + return; + } + switch (cmd->oc) + { + case OC_END: + result = GNUNET_OK; + GNUNET_SCHEDULER_shutdown (); + return; + case OC_ADMIN_ADD_INCOMING: + if (NULL != + cmd->details.admin_add_incoming.reserve_reference) + { + ref = find_command (is, + cmd->details.admin_add_incoming.reserve_reference); + GNUNET_assert (NULL != ref); + GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); + cmd->details.admin_add_incoming.reserve_priv + = ref->details.admin_add_incoming.reserve_priv; + } + else + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + priv = GNUNET_CRYPTO_eddsa_key_create (); + cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv; + GNUNET_free (priv); + } + GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv, + &reserve_pub.eddsa_pub); + if (GNUNET_OK != + TALER_string_to_amount (cmd->details.admin_add_incoming.amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + cmd->details.admin_add_incoming.amount, + is->ip); + fail (is); + return; + } + wire = json_loads (cmd->details.admin_add_incoming.wire, + JSON_REJECT_DUPLICATES, + NULL); + if (NULL == wire) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse wire details `%s' at %u\n", + cmd->details.admin_add_incoming.wire, + is->ip); + fail (is); + return; + } + execution_date = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (&execution_date); + cmd->details.admin_add_incoming.aih + = TALER_EXCHANGE_admin_add_incoming (exchange, + &reserve_pub, + &amount, + execution_date, + wire, + &add_incoming_cb, + is); + if (NULL == cmd->details.admin_add_incoming.aih) + { + GNUNET_break (0); + fail (is); + return; + } + trigger_context_task (); + return; + case OC_WITHDRAW_STATUS: + GNUNET_assert (NULL != + cmd->details.reserve_status.reserve_reference); + ref = find_command (is, + cmd->details.reserve_status.reserve_reference); + GNUNET_assert (NULL != ref); + GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); + GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv, + &reserve_pub.eddsa_pub); + cmd->details.reserve_status.wsh + = TALER_EXCHANGE_reserve_status (exchange, + &reserve_pub, + &reserve_status_cb, + is); + trigger_context_task (); + return; + case OC_WITHDRAW_SIGN: + GNUNET_assert (NULL != + cmd->details.reserve_withdraw.reserve_reference); + ref = find_command (is, + cmd->details.reserve_withdraw.reserve_reference); + GNUNET_assert (NULL != ref); + GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); + if (NULL != cmd->details.reserve_withdraw.amount) + { + if (GNUNET_OK != + TALER_string_to_amount (cmd->details.reserve_withdraw.amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + cmd->details.reserve_withdraw.amount, + is->ip); + fail (is); + return; + } + cmd->details.reserve_withdraw.pk = find_pk (is->keys, + &amount); + } + if (NULL == cmd->details.reserve_withdraw.pk) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to determine denomination key at %u\n", + is->ip); + fail (is); + return; + } + + /* create coin's private key */ + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + priv = GNUNET_CRYPTO_eddsa_key_create (); + cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv; + GNUNET_free (priv); + } + GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key + = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key)); + cmd->details.reserve_withdraw.wsh + = TALER_EXCHANGE_reserve_withdraw (exchange, + cmd->details.reserve_withdraw.pk, + &ref->details.admin_add_incoming.reserve_priv, + &cmd->details.reserve_withdraw.coin_priv, + &cmd->details.reserve_withdraw.blinding_key, + &reserve_withdraw_cb, + is); + if (NULL == cmd->details.reserve_withdraw.wsh) + { + GNUNET_break (0); + fail (is); + return; + } + trigger_context_task (); + return; + case OC_DEPOSIT: + { + struct GNUNET_HashCode h_contract; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + const struct TALER_EXCHANGE_DenomPublicKey *coin_pk; + const struct TALER_DenominationSignature *coin_pk_sig; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinSpendSignatureP coin_sig; + struct GNUNET_TIME_Absolute refund_deadline; + struct GNUNET_TIME_Absolute wire_deadline; + struct GNUNET_TIME_Absolute timestamp; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct TALER_MerchantPublicKeyP merchant_pub; + json_t *contract; + json_t *wire; + + GNUNET_assert (NULL != + cmd->details.deposit.coin_ref); + ref = find_command (is, + cmd->details.deposit.coin_ref); + GNUNET_assert (NULL != ref); + switch (ref->oc) + { + case OC_WITHDRAW_SIGN: + coin_priv = &ref->details.reserve_withdraw.coin_priv; + coin_pk = ref->details.reserve_withdraw.pk; + coin_pk_sig = &ref->details.reserve_withdraw.sig; + break; + case OC_REFRESH_REVEAL: + { + const struct FreshCoin *fc; + unsigned int idx; + + idx = cmd->details.deposit.coin_idx; + GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins); + fc = &ref->details.refresh_reveal.fresh_coins[idx]; + + coin_priv = &fc->coin_priv; + coin_pk = fc->pk; + coin_pk_sig = &fc->sig; + } + break; + default: + GNUNET_assert (0); + } + if (GNUNET_OK != + TALER_string_to_amount (cmd->details.deposit.amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + cmd->details.deposit.amount, + is->ip); + fail (is); + return; + } + contract = json_loads (cmd->details.deposit.contract, + JSON_REJECT_DUPLICATES, + NULL); + if (NULL == contract) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse contract details `%s' at %u/%s\n", + cmd->details.deposit.contract, + is->ip, + cmd->label); + fail (is); + return; + } + TALER_hash_json (contract, + &h_contract); + wire = json_loads (cmd->details.deposit.wire_details, + JSON_REJECT_DUPLICATES, + NULL); + if (NULL == wire) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse wire details `%s' at %u/%s\n", + cmd->details.deposit.wire_details, + is->ip, + cmd->label); + fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + + priv = GNUNET_CRYPTO_eddsa_key_create (); + cmd->details.deposit.merchant_priv.eddsa_priv = *priv; + GNUNET_free (priv); + if (0 != cmd->details.deposit.refund_deadline.rel_value_us) + { + refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline); + } + else + { + refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS; + } + GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv, + &merchant_pub.eddsa_pub); + + wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS); + timestamp = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (×tamp); + { + struct TALER_DepositRequestPS dr; + + memset (&dr, 0, sizeof (dr)); + dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.h_contract = h_contract; + TALER_hash_json (wire, + &dr.h_wire); + dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + dr.transaction_id = GNUNET_htonll (cmd->details.deposit.transaction_id); + TALER_amount_hton (&dr.amount_with_fee, + &amount); + TALER_amount_hton (&dr.deposit_fee, + &coin_pk->fee_deposit); + dr.merchant = merchant_pub; + dr.coin_pub = coin_pub; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &dr.purpose, + &coin_sig.eddsa_signature)); + } + cmd->details.deposit.dh + = TALER_EXCHANGE_deposit (exchange, + &amount, + wire_deadline, + wire, + &h_contract, + &coin_pub, + coin_pk_sig, + &coin_pk->key, + timestamp, + cmd->details.deposit.transaction_id, + &merchant_pub, + refund_deadline, + &coin_sig, + &deposit_cb, + is); + if (NULL == cmd->details.deposit.dh) + { + GNUNET_break (0); + json_decref (wire); + fail (is); + return; + } + json_decref (wire); + trigger_context_task (); + return; + } + case OC_REFRESH_MELT: + { + unsigned int num_melted_coins; + unsigned int num_fresh_coins; + + cmd->details.refresh_melt.noreveal_index = UINT16_MAX; + for (num_melted_coins=0; + NULL != cmd->details.refresh_melt.melted_coins[num_melted_coins].amount; + num_melted_coins++) ; + for (num_fresh_coins=0; + NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins]; + num_fresh_coins++) ; + + cmd->details.refresh_melt.fresh_pks + = GNUNET_new_array (num_fresh_coins, + const struct TALER_EXCHANGE_DenomPublicKey *); + { + struct TALER_CoinSpendPrivateKeyP melt_privs[num_melted_coins]; + struct TALER_Amount melt_amounts[num_melted_coins]; + struct TALER_DenominationSignature melt_sigs[num_melted_coins]; + struct TALER_EXCHANGE_DenomPublicKey melt_pks[num_melted_coins]; + struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins]; + unsigned int i; + + for (i=0;i<num_melted_coins;i++) + { + const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coins[i]; + ref = find_command (is, + md->coin_ref); + GNUNET_assert (NULL != ref); + GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc); + + melt_privs[i] = ref->details.reserve_withdraw.coin_priv; + if (GNUNET_OK != + TALER_string_to_amount (md->amount, + &melt_amounts[i])) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + md->amount, + is->ip); + fail (is); + return; + } + melt_sigs[i] = ref->details.reserve_withdraw.sig; + melt_pks[i] = *ref->details.reserve_withdraw.pk; + } + for (i=0;i<num_fresh_coins;i++) + { + if (GNUNET_OK != + TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i], + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + cmd->details.reserve_withdraw.amount, + is->ip); + fail (is); + return; + } + cmd->details.refresh_melt.fresh_pks[i] + = find_pk (is->keys, + &amount); + fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i]; + } + cmd->details.refresh_melt.refresh_data + = TALER_EXCHANGE_refresh_prepare (num_melted_coins, + melt_privs, + melt_amounts, + melt_sigs, + melt_pks, + GNUNET_YES, + num_fresh_coins, + fresh_pks, + &cmd->details.refresh_melt.refresh_data_length); + if (NULL == cmd->details.refresh_melt.refresh_data) + { + GNUNET_break (0); + fail (is); + return; + } + cmd->details.refresh_melt.rmh + = TALER_EXCHANGE_refresh_melt (exchange, + cmd->details.refresh_melt.refresh_data_length, + cmd->details.refresh_melt.refresh_data, + &melt_cb, + is); + if (NULL == cmd->details.refresh_melt.rmh) + { + GNUNET_break (0); + fail (is); + return; + } + } + } + trigger_context_task (); + return; + case OC_REFRESH_REVEAL: + ref = find_command (is, + cmd->details.refresh_reveal.melt_ref); + cmd->details.refresh_reveal.rrh + = TALER_EXCHANGE_refresh_reveal (exchange, + ref->details.refresh_melt.refresh_data_length, + ref->details.refresh_melt.refresh_data, + ref->details.refresh_melt.noreveal_index, + &reveal_cb, + is); + if (NULL == cmd->details.refresh_reveal.rrh) + { + GNUNET_break (0); + fail (is); + return; + } + trigger_context_task (); + return; + case OC_REFRESH_LINK: + /* find reveal command */ + ref = find_command (is, + cmd->details.refresh_link.reveal_ref); + /* find melt command */ + ref = find_command (is, + ref->details.refresh_reveal.melt_ref); + /* find reserve_withdraw command */ + { + unsigned int idx; + const struct MeltDetails *md; + unsigned int num_melted_coins; + + for (num_melted_coins=0; + NULL != ref->details.refresh_melt.melted_coins[num_melted_coins].amount; + num_melted_coins++) ; + idx = cmd->details.refresh_link.coin_idx; + GNUNET_assert (idx < num_melted_coins); + md = &ref->details.refresh_melt.melted_coins[idx]; + ref = find_command (is, + md->coin_ref); + } + GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc); + /* finally, use private key from withdraw sign command */ + cmd->details.refresh_link.rlh + = TALER_EXCHANGE_refresh_link (exchange, + &ref->details.reserve_withdraw.coin_priv, + &link_cb, + is); + if (NULL == cmd->details.refresh_link.rlh) + { + GNUNET_break (0); + fail (is); + return; + } + trigger_context_task (); + return; + case OC_WIRE: + cmd->details.wire.wh = TALER_EXCHANGE_wire (exchange, + &wire_cb, + is); + trigger_context_task (); + return; + case OC_WIRE_DEPOSITS: + if (NULL != cmd->details.wire_deposits.wtid_ref) + { + ref = find_command (is, + cmd->details.wire_deposits.wtid_ref); + GNUNET_assert (NULL != ref); + cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid; + } + cmd->details.wire_deposits.wdh + = TALER_EXCHANGE_wire_deposits (exchange, + &cmd->details.wire_deposits.wtid, + &wire_deposits_cb, + is); + trigger_context_task (); + return; + case OC_DEPOSIT_WTID: + { + struct GNUNET_HashCode h_wire; + struct GNUNET_HashCode h_contract; + json_t *wire; + json_t *contract; + const struct Command *coin; + struct TALER_CoinSpendPublicKeyP coin_pub; + + ref = find_command (is, + cmd->details.deposit_wtid.deposit_ref); + GNUNET_assert (NULL != ref); + coin = find_command (is, + ref->details.deposit.coin_ref); + GNUNET_assert (NULL != coin); + switch (coin->oc) + { + case OC_WITHDRAW_SIGN: + GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + break; + case OC_REFRESH_REVEAL: + { + const struct FreshCoin *fc; + unsigned int idx; + + idx = ref->details.deposit.coin_idx; + GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins); + fc = &coin->details.refresh_reveal.fresh_coins[idx]; + + GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + } + break; + default: + GNUNET_assert (0); + } + + wire = json_loads (ref->details.deposit.wire_details, + JSON_REJECT_DUPLICATES, + NULL); + GNUNET_assert (NULL != wire); + TALER_hash_json (wire, + &h_wire); + json_decref (wire); + contract = json_loads (ref->details.deposit.contract, + JSON_REJECT_DUPLICATES, + NULL); + GNUNET_assert (NULL != contract); + TALER_hash_json (contract, + &h_contract); + json_decref (contract); + cmd->details.deposit_wtid.dwh + = TALER_EXCHANGE_deposit_wtid (exchange, + &ref->details.deposit.merchant_priv, + &h_wire, + &h_contract, + &coin_pub, + ref->details.deposit.transaction_id, + &deposit_wtid_cb, + is); + trigger_context_task (); + } + return; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown instruction %d at %u (%s)\n", + cmd->oc, + is->ip, + cmd->label); + fail (is); + return; + } +} + + +/** + * Function run when the test terminates (good or bad). + * Cleans up our state. + * + * @param cls the interpreter state. + * @param tc unused + */ +static void +do_shutdown (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InterpreterState *is = cls; + struct Command *cmd; + unsigned int i; + + shutdown_task = NULL; + for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++) + { + switch (cmd->oc) + { + case OC_END: + GNUNET_assert (0); + break; + case OC_ADMIN_ADD_INCOMING: + if (NULL != cmd->details.admin_add_incoming.aih) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih); + cmd->details.admin_add_incoming.aih = NULL; + } + break; + case OC_WITHDRAW_STATUS: + if (NULL != cmd->details.reserve_status.wsh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_reserve_status_cancel (cmd->details.reserve_status.wsh); + cmd->details.reserve_status.wsh = NULL; + } + break; + case OC_WITHDRAW_SIGN: + if (NULL != cmd->details.reserve_withdraw.wsh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh); + cmd->details.reserve_withdraw.wsh = NULL; + } + if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature) + { + GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature); + cmd->details.reserve_withdraw.sig.rsa_signature = NULL; + } + if (NULL != cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key) + { + GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key); + cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key = NULL; + } + break; + case OC_DEPOSIT: + if (NULL != cmd->details.deposit.dh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_deposit_cancel (cmd->details.deposit.dh); + cmd->details.deposit.dh = NULL; + } + break; + case OC_REFRESH_MELT: + if (NULL != cmd->details.refresh_melt.rmh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_refresh_melt_cancel (cmd->details.refresh_melt.rmh); + cmd->details.refresh_melt.rmh = NULL; + } + GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks); + cmd->details.refresh_melt.fresh_pks = NULL; + GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data); + cmd->details.refresh_melt.refresh_data = NULL; + cmd->details.refresh_melt.refresh_data_length = 0; + break; + case OC_REFRESH_REVEAL: + if (NULL != cmd->details.refresh_reveal.rrh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh); + cmd->details.refresh_reveal.rrh = NULL; + } + { + unsigned int j; + struct FreshCoin *fresh_coins; + + fresh_coins = cmd->details.refresh_reveal.fresh_coins; + for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++) + GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature); + } + GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins); + cmd->details.refresh_reveal.fresh_coins = NULL; + cmd->details.refresh_reveal.num_fresh_coins = 0; + break; + case OC_REFRESH_LINK: + if (NULL != cmd->details.refresh_link.rlh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_refresh_link_cancel (cmd->details.refresh_link.rlh); + cmd->details.refresh_link.rlh = NULL; + } + break; + case OC_WIRE: + if (NULL != cmd->details.wire.wh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_wire_cancel (cmd->details.wire.wh); + cmd->details.wire.wh = NULL; + } + break; + case OC_WIRE_DEPOSITS: + if (NULL != cmd->details.wire_deposits.wdh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_wire_deposits_cancel (cmd->details.wire_deposits.wdh); + cmd->details.wire_deposits.wdh = NULL; + } + break; + case OC_DEPOSIT_WTID: + if (NULL != cmd->details.deposit_wtid.dwh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + i, + cmd->label); + TALER_EXCHANGE_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh); + cmd->details.deposit_wtid.dwh = NULL; + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown instruction %d at %u (%s)\n", + cmd->oc, + i, + cmd->label); + break; + } + } + if (NULL != is->task) + { + GNUNET_SCHEDULER_cancel (is->task); + is->task = NULL; + } + GNUNET_free (is); + if (NULL != ctx_task) + { + GNUNET_SCHEDULER_cancel (ctx_task); + ctx_task = NULL; + } + if (NULL != exchange) + { + TALER_EXCHANGE_disconnect (exchange); + exchange = NULL; + } + if (NULL != ctx) + { + TALER_EXCHANGE_fini (ctx); + ctx = NULL; + } +} + + +/** + * Functions of this type are called to provide the retrieved signing and + * denomination keys of the exchange. No TALER_EXCHANGE_*() functions should be called + * in this callback. + * + * @param cls closure + * @param keys information about keys of the exchange + */ +static void +cert_cb (void *cls, + const struct TALER_EXCHANGE_Keys *keys) +{ + struct InterpreterState *is = cls; + + /* check that keys is OK */ +#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0) + ERR (NULL == keys); + ERR (0 == keys->num_sign_keys); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read %u signing keys\n", + keys->num_sign_keys); + ERR (0 == keys->num_denom_keys); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read %u denomination keys\n", + keys->num_denom_keys); +#undef ERR + + /* run actual tests via interpreter-loop */ + is->keys = keys; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Task that runs the context's event loop with the GNUnet scheduler. + * + * @param cls unused + * @param tc scheduler context (unused) + */ +static void +context_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + long timeout; + int max_fd; + fd_set read_fd_set; + fd_set write_fd_set; + fd_set except_fd_set; + struct GNUNET_NETWORK_FDSet *rs; + struct GNUNET_NETWORK_FDSet *ws; + struct GNUNET_TIME_Relative delay; + + ctx_task = NULL; + TALER_EXCHANGE_perform (ctx); + max_fd = -1; + timeout = -1; + FD_ZERO (&read_fd_set); + FD_ZERO (&write_fd_set); + FD_ZERO (&except_fd_set); + TALER_EXCHANGE_get_select_info (ctx, + &read_fd_set, + &write_fd_set, + &except_fd_set, + &max_fd, + &timeout); + if (timeout >= 0) + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout); + else + delay = GNUNET_TIME_UNIT_FOREVER_REL; + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (rs, + &read_fd_set, + max_fd + 1); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (ws, + &write_fd_set, + max_fd + 1); + ctx_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + delay, + rs, + ws, + &context_task, + cls); + GNUNET_NETWORK_fdset_destroy (rs); + GNUNET_NETWORK_fdset_destroy (ws); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InterpreterState *is; + static struct MeltDetails melt_coins_1[] = { + { .amount = "EUR:4", + .coin_ref = "refresh-withdraw-coin-1" }, + { NULL, NULL } + }; + static const char *melt_fresh_amounts_1[] = { + "EUR:1", + "EUR:1", + "EUR:1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.1", + "EUR:0.01", + "EUR:0.01", + "EUR:0.01", + "EUR:0.01", + "EUR:0.01", + "EUR:0.01", + /* with 0.01 withdraw fees (except for 1ct coins), + this totals up to exactly EUR:3.97, and with + the 0.03 refresh fee, to EUR:4.0*/ + NULL + }; + static struct Command commands[] = + { + /* *************** start of /wire testing ************** */ + +#if WIRE_TEST + { .oc = OC_WIRE, + .label = "wire-test", + /* /wire/test replies with a 302 redirect */ + .expected_response_code = MHD_HTTP_FOUND, + .details.wire.format = "test" }, +#endif +#if WIRE_SEPA + { .oc = OC_WIRE, + .label = "wire-sepa", + /* /wire/sepa replies with a 200 redirect */ + .expected_response_code = MHD_HTTP_OK, + .details.wire.format = "sepa" }, +#endif + /* *************** end of /wire testing ************** */ + +#if WIRE_TEST + /* None of this works if 'test' is not allowed as we do + /admin/add/incoming with format 'test' */ + + /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */ + { .oc = OC_ADMIN_ADD_INCOMING, + .label = "create-reserve-1", + .expected_response_code = MHD_HTTP_OK, + .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":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 exchange knows about the deposit, but has no WTID yet. */ + { .oc = OC_DEPOSIT_WTID, + .label = "deposit-wtid-found", + .expected_response_code = MHD_HTTP_ACCEPTED, + .details.deposit_wtid.deposit_ref = "deposit-simple" }, + /* Try resolving a deposit's WTID for a failed deposit. + As the deposit failed, the answer should be that + the exchange does NOT know about the deposit. */ + { .oc = OC_DEPOSIT_WTID, + .label = "deposit-wtid-failing", + .expected_response_code = MHD_HTTP_NOT_FOUND, + .details.deposit_wtid.deposit_ref = "deposit-double-2" }, + /* Try resolving an undefined (all zeros) WTID; this + should fail as obviously the exchange didn't use that + WTID value for any transaction. */ + { .oc = OC_WIRE_DEPOSITS, + .label = "wire-deposit-failing", + .expected_response_code = MHD_HTTP_NOT_FOUND }, + + /* TODO: trigger aggregation logic and then check the + cases where tracking succeeds! */ + + /* ************** End of tracking API testing************* */ + + +#endif + + { .oc = OC_END } + }; + + is = GNUNET_new (struct InterpreterState); + is->commands = commands; + + ctx = TALER_EXCHANGE_init (); + GNUNET_assert (NULL != ctx); + ctx_task = GNUNET_SCHEDULER_add_now (&context_task, + ctx); + exchange = TALER_EXCHANGE_connect (ctx, + "http://localhost:8081", + &cert_cb, is, + TALER_EXCHANGE_OPTION_END); + GNUNET_assert (NULL != exchange); + shutdown_task + = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 150), + &do_shutdown, is); +} + + +/** + * Main function for the testcase for the exchange API. + * + * @param argc expected to be 1 + * @param argv expected to only contain the program name + */ +int +main (int argc, + char * const *argv) +{ + struct GNUNET_OS_Process *proc; + struct GNUNET_OS_Process *exchanged; + + GNUNET_log_setup ("test-exchange-api", + "WARNING", + NULL); + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-keyup", + "taler-exchange-keyup", + "-d", "test-exchange-home", + "-m", "test-exchange-home/master.priv", + NULL); + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + exchanged = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-httpd", + "taler-exchange-httpd", + "-d", "test-exchange-home", + NULL); + /* give child time to start and bind against the socket */ + fprintf (stderr, "Waiting for taler-exchange-httpd to be ready"); + do + { + fprintf (stderr, "."); + sleep (1); + } + while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null")); + fprintf (stderr, "\n"); + result = GNUNET_SYSERR; + GNUNET_SCHEDULER_run (&run, NULL); + GNUNET_OS_process_kill (exchanged, + SIGTERM); + GNUNET_OS_process_wait (exchanged); + GNUNET_OS_process_destroy (exchanged); + return (GNUNET_OK == result) ? 0 : 1; +} + +/* end of test_exchange_api.c */ diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am new file mode 100644 index 000000000..4ffabd15d --- /dev/null +++ b/src/exchange-tools/Makefile.am @@ -0,0 +1,81 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +bin_PROGRAMS = \ + taler-auditor-sign \ + taler-exchange-keyup \ + taler-exchange-keycheck \ + taler-exchange-reservemod \ + taler-exchange-sepa \ + taler-exchange-dbinit + +taler_exchange_keyup_SOURCES = \ + taler-exchange-keyup.c +taler_exchange_keyup_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lgnunetutil $(XLIB) +taler_exchange_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS) + +taler_auditor_sign_SOURCES = \ + taler-auditor-sign.c +taler_auditor_sign_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lgnunetutil $(XLIB) + + +taler_exchange_sepa_SOURCES = \ + taler-exchange-sepa.c +taler_exchange_sepa_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil -ljansson $(XLIB) +taler_exchange_sepa_LDFLAGS = $(POSTGRESQL_LDFLAGS) + +taler_exchange_keycheck_SOURCES = \ + taler-exchange-keycheck.c +taler_exchange_keycheck_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lgnunetutil $(XLIB) +taler_exchange_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS) + +taler_exchange_reservemod_SOURCES = \ + taler-exchange-reservemod.c +taler_exchange_reservemod_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lgnunetutil -ljansson $(XLIB) +taler_exchange_reservemod_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) +taler_exchange_reservemod_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/pq/ \ + $(POSTGRESQL_CPPFLAGS) + +taler_exchange_dbinit_SOURCES = \ + taler-exchange-dbinit.c +taler_exchange_dbinit_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lgnunetutil $(XLIB) +taler_exchange_dbinit_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) +taler_exchange_dbinit_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/pq/ \ + $(POSTGRESQL_CPPFLAGS) diff --git a/src/exchange-tools/taler-auditor-sign.c b/src/exchange-tools/taler-auditor-sign.c new file mode 100644 index 000000000..e4821f411 --- /dev/null +++ b/src/exchange-tools/taler-auditor-sign.c @@ -0,0 +1,321 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-auditor-sign.c + * @brief Tool used by the auditor to sign the exchange's master key and the + * denomination key(s). + * @author Christian Grothoff + */ +#include <platform.h> +#include "taler_exchangedb_lib.h" + + +/** + * Are we running in verbose mode? + */ +static int verbose; + +/** + * Filename of the auditor's private key. + */ +static char *auditor_key_file; + +/** + * Exchange's public key (in Crockford base32 encoding). + */ +static char *exchange_public_key; + +/** + * File with the Exchange's denomination keys to sign, itself + * signed by the Exchange's public key. + */ +static char *exchange_request_file; + +/** + * Where should we write the auditor's signature? + */ +static char *output_file; + +/** + * Master public key of the exchange. + */ +static struct TALER_MasterPublicKeyP master_public_key; + + +/** + * Print denomination key details for diagnostics. + * + * @param dk denomination key to print + */ +static void +print_dk (const struct TALER_DenominationKeyValidityPS *dk) +{ + struct TALER_Amount a; + char *s; + + fprintf (stdout, + "Denomination key hash: %s\n", + GNUNET_h2s_full (&dk->denom_hash)); + TALER_amount_ntoh (&a, + &dk->value); + fprintf (stdout, + "Value: %s\n", + s = TALER_amount_to_string (&a)); + GNUNET_free (s); + TALER_amount_ntoh (&a, + &dk->fee_withdraw); + fprintf (stdout, + "Withdraw fee: %s\n", + s = TALER_amount_to_string (&a)); + GNUNET_free (s); + TALER_amount_ntoh (&a, + &dk->fee_deposit); + fprintf (stdout, + "Deposit fee: %s\n", + s = TALER_amount_to_string (&a)); + GNUNET_free (s); + TALER_amount_ntoh (&a, + &dk->fee_refresh); + fprintf (stdout, + "Refresh fee: %s\n", + s = TALER_amount_to_string (&a)); + GNUNET_free (s); + + fprintf (stdout, + "Validity start time: %s\n", + GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->start))); + fprintf (stdout, + "Withdraw end time: %s\n", + GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_withdraw))); + fprintf (stdout, + "Deposit end time: %s\n", + GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_spend))); + fprintf (stdout, + "Legal dispute end time: %s\n", + GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_legal))); + + fprintf (stdout, + "\n"); +} + + +/** + * The main function of the taler-auditor-sign tool. This tool is used + * to sign a exchange's master and denomination keys, affirming that the + * auditor is aware of them and will validate the exchange's database with + * respect to these keys. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "auditor-key", "FILE", + "file containing the private key of the auditor", 1, + &GNUNET_GETOPT_set_filename, &auditor_key_file}, + TALER_GETOPT_OPTION_HELP ("Private key of the auditor to use for signing"), + {'m', "exchange-key", "KEY", + "public key of the exchange (Crockford base32 encoded)", 1, + &GNUNET_GETOPT_set_filename, &exchange_public_key}, + {'r', "exchange-request", "FILE", + "set of keys the exchange requested the auditor to sign", 1, + &GNUNET_GETOPT_set_string, &exchange_request_file}, + {'o', "output", "FILE", + "where to write our signature", 1, + &GNUNET_GETOPT_set_string, &output_file}, + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_VERBOSE (&verbose), + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; + struct TALER_AuditorSignatureP *sigs; + struct TALER_AuditorPublicKeyP apub; + struct GNUNET_DISK_FileHandle *fh; + struct TALER_DenominationKeyValidityPS *dks; + unsigned int dks_len; + struct TALER_ExchangeKeyValidityPS kv; + off_t in_size; + unsigned int i; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-keyup", + "WARNING", + NULL)); + if (GNUNET_GETOPT_run ("taler-exchange-keyup", + options, + argc, argv) < 0) + return 1; + if (NULL == auditor_key_file) + { + fprintf (stderr, + "Auditor key file not given\n"); + return 1; + } + eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (auditor_key_file); + if (NULL == eddsa_priv) + { + fprintf (stderr, + "Failed to initialize auditor key from file `%s'\n", + auditor_key_file); + return 1; + } + GNUNET_CRYPTO_eddsa_key_get_public (eddsa_priv, + &apub.eddsa_pub); + if (NULL == exchange_public_key) + { + fprintf (stderr, + "Exchange public key not given\n"); + GNUNET_free (eddsa_priv); + return 1; + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (exchange_public_key, + strlen (exchange_public_key), + &master_public_key, + sizeof (master_public_key))) + { + fprintf (stderr, + "Public key `%s' malformed\n", + exchange_public_key); + GNUNET_free (eddsa_priv); + return 1; + } + if (NULL == exchange_request_file) + { + fprintf (stderr, + "Exchange signing request not given\n"); + GNUNET_free (eddsa_priv); + return 1; + } + fh = GNUNET_DISK_file_open (exchange_request_file, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fh) + { + fprintf (stderr, + "Failed to open file `%s': %s\n", + exchange_request_file, + STRERROR (errno)); + GNUNET_free (eddsa_priv); + return 1; + } + if (GNUNET_OK != + GNUNET_DISK_file_handle_size (fh, + &in_size)) + { + fprintf (stderr, + "Failed to obtain input file size `%s': %s\n", + exchange_request_file, + STRERROR (errno)); + GNUNET_DISK_file_close (fh); + GNUNET_free (eddsa_priv); + return 1; + } + if (0 != (in_size % sizeof (struct TALER_DenominationKeyValidityPS))) + { + fprintf (stderr, + "Input file size of file `%s' is invalid\n", + exchange_request_file); + GNUNET_DISK_file_close (fh); + GNUNET_free (eddsa_priv); + return 1; + } + dks_len = in_size / sizeof (struct TALER_DenominationKeyValidityPS); + kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); + kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); + kv.master = master_public_key; + dks = GNUNET_new_array (dks_len, + struct TALER_DenominationKeyValidityPS); + sigs = GNUNET_new_array (dks_len, + struct TALER_AuditorSignatureP); + if (in_size != + GNUNET_DISK_file_read (fh, + dks, + in_size)) + { + fprintf (stderr, + "Failed to read input file `%s': %s\n", + exchange_request_file, + STRERROR (errno)); + GNUNET_DISK_file_close (fh); + GNUNET_free (sigs); + GNUNET_free (dks); + GNUNET_free (eddsa_priv); + return 1; + } + GNUNET_DISK_file_close (fh); + for (i=0;i<dks_len;i++) + { + struct TALER_DenominationKeyValidityPS *dk = &dks[i]; + + if (verbose) + print_dk (dk); + kv.start = dk->start; + kv.expire_withdraw = dk->expire_withdraw; + kv.expire_spend = dk->expire_spend; + kv.expire_legal = dk->expire_legal; + kv.value = dk->value; + kv.fee_withdraw = dk->fee_withdraw; + kv.fee_deposit = dk->fee_deposit; + kv.fee_refresh = dk->fee_refresh; + kv.denom_hash = dk->denom_hash; + + /* Finally sign ... */ + GNUNET_CRYPTO_eddsa_sign (eddsa_priv, + &kv.purpose, + &sigs[i].eddsa_sig); + + + } + + if (NULL == output_file) + { + fprintf (stderr, + "Output file not given\n"); + GNUNET_free (dks); + GNUNET_free (sigs); + GNUNET_free (eddsa_priv); + return 1; + } + + /* write result to disk */ + if (GNUNET_OK != + TALER_EXCHANGEDB_auditor_write (output_file, + &apub, + sigs, + &master_public_key, + dks_len, + dks)) + { + fprintf (stderr, + "Failed to write to file `%s': %s\n", + output_file, + STRERROR (errno)); + GNUNET_free (sigs); + GNUNET_free (dks); + return 1; + } + GNUNET_free (sigs); + GNUNET_free (dks); + GNUNET_free (eddsa_priv); + return 0; +} + +/* end of taler-auditor-sign.c */ diff --git a/src/exchange-tools/taler-exchange-dbinit.c b/src/exchange-tools/taler-exchange-dbinit.c new file mode 100644 index 000000000..43a070228 --- /dev/null +++ b/src/exchange-tools/taler-exchange-dbinit.c @@ -0,0 +1,105 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-tools/taler-exchange-dbinit.c + * @brief Create tables for the exchange database. + * @author Florian Dold + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <libpq-fe.h> +#include "taler_exchangedb_plugin.h" + +/** + * Exchange directory with the keys. + */ +static char *exchange_base_dir; + +/** + * Our configuration. + */ +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Our DB plugin. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; + + +/** + * The main function of the database initialization tool. + * Used to initialize the Taler Exchange's database. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'d', "exchange-dir", "DIR", + "exchange directory", 1, + &GNUNET_GETOPT_set_filename, &exchange_base_dir}, + GNUNET_GETOPT_OPTION_HELP ("Initialize Taler Exchange database"), + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + + if (GNUNET_GETOPT_run ("taler-exchange-dbinit", + options, + argc, argv) < 0) + return 1; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-dbinit", + "INFO", + NULL)); + if (NULL == exchange_base_dir) + { + fprintf (stderr, + "Exchange base directory not given.\n"); + return 1; + } + cfg = TALER_config_load (exchange_base_dir); + if (NULL == cfg) + { + fprintf (stderr, + "Failed to load exchange configuration.\n"); + return 1; + } + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + fprintf (stderr, + "Failed to initialize database plugin.\n"); + return 1; + } + if (GNUNET_OK != + plugin->create_tables (plugin->cls, + GNUNET_NO)) + { + fprintf (stderr, + "Failed to initialize database.\n"); + TALER_EXCHANGEDB_plugin_unload (plugin); + return 1; + } + TALER_EXCHANGEDB_plugin_unload (plugin); + return 0; +} + +/* end of taler-exchange-dbinit.c */ diff --git a/src/exchange-tools/taler-exchange-keycheck.c b/src/exchange-tools/taler-exchange-keycheck.c new file mode 100644 index 000000000..d6566cd03 --- /dev/null +++ b/src/exchange-tools/taler-exchange-keycheck.c @@ -0,0 +1,247 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-keycheck.c + * @brief Check exchange keys for validity. Reads the signing and denomination + * keys from the exchange directory and checks to make sure they are + * well-formed. This is purely a diagnostic tool. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include <platform.h> +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchangedb_lib.h" + +/** + * Exchange directory with the keys. + */ +static char *exchange_directory; + +/** + * Our configuration. + */ +static struct GNUNET_CONFIGURATION_Handle *kcfg; + + +/** + * Function called on each signing key. + * + * @param cls closure (NULL) + * @param filename name of the file the key came from + * @param ski the sign key + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +signkeys_iter (void *cls, + const char *filename, + const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Iterating over key `%s' for start time %s\n", + filename, + GNUNET_STRINGS_absolute_time_to_string + (GNUNET_TIME_absolute_ntoh (ski->issue.start))); + + if (ntohl (ski->issue.purpose.size) != + (sizeof (struct TALER_ExchangeSigningKeyValidityPS) - + offsetof (struct TALER_ExchangeSigningKeyValidityPS, + purpose))) + { + fprintf (stderr, + "Signing key `%s' has invalid purpose size\n", + filename); + return GNUNET_SYSERR; + } + if ( (0 != GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us % 1000000) || + (0 != GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us % 1000000) || + (0 != GNUNET_TIME_absolute_ntoh (ski->issue.end).abs_value_us % 1000000) ) + { + fprintf (stderr, + "Timestamps are not multiples of a round second\n"); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, + &ski->issue.purpose, + &ski->issue.signature.eddsa_signature, + &ski->issue.master_public_key.eddsa_pub)) + { + fprintf (stderr, + "Signing key `%s' has invalid signature\n", + filename); + return GNUNET_SYSERR; + } + printf ("Signing key `%s' valid\n", + filename); + return GNUNET_OK; +} + + +/** + * Check signing keys. + * + * @return #GNUNET_OK if the keys are OK + * #GNUNET_NO if not + */ +static int +exchange_signkeys_check () +{ + if (0 > TALER_EXCHANGEDB_signing_keys_iterate (exchange_directory, + &signkeys_iter, + NULL)) + return GNUNET_NO; + return GNUNET_OK; +} + + +/** + * Function called on each denomination key. + * + * @param cls closure (NULL) + * @param dki the denomination key + * @param alias coin alias + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +denomkeys_iter (void *cls, + const char *alias, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + struct GNUNET_HashCode hc; + + if (ntohl (dki->issue.properties.purpose.size) != + sizeof (struct TALER_DenominationKeyValidityPS)) + { + fprintf (stderr, + "Denomination key for `%s' has invalid purpose size\n", + alias); + return GNUNET_SYSERR; + } + + if ( (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us % 1000000) || + (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us % 1000000) || + (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_legal).abs_value_us % 1000000) || + (0 != GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us % 1000000) ) + { + fprintf (stderr, + "Timestamps are not multiples of a round second\n"); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, + &dki->issue.properties.purpose, + &dki->issue.signature.eddsa_signature, + &dki->issue.properties.master.eddsa_pub)) + { + fprintf (stderr, + "Denomination key for `%s' has invalid signature\n", + alias); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key, + &hc); + if (0 != memcmp (&hc, + &dki->issue.properties.denom_hash, + sizeof (struct GNUNET_HashCode))) + { + fprintf (stderr, + "Public key for `%s' does not match signature\n", + alias); + return GNUNET_SYSERR; + } + printf ("Denomination key `%s' is valid\n", + alias); + + return GNUNET_OK; +} + + +/** + * Check denomination keys. + * + * @return #GNUNET_OK if the keys are OK + * #GNUNET_NO if not + */ +static int +exchange_denomkeys_check () +{ + if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory, + &denomkeys_iter, + NULL)) + return GNUNET_NO; + return GNUNET_OK; +} + + +/** + * The main function of the keyup tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_HELP ("gnunet-exchange-keycheck OPTIONS"), + {'d', "directory", "DIRECTORY", + "exchange directory with keys to check", 1, + &GNUNET_GETOPT_set_filename, &exchange_directory}, + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-keycheck", + "WARNING", + NULL)); + + if (GNUNET_GETOPT_run ("taler-exchange-keycheck", + options, + argc, argv) < 0) + return 1; + if (NULL == exchange_directory) + { + fprintf (stderr, + "Exchange directory not given\n"); + return 1; + } + + kcfg = TALER_config_load (exchange_directory); + if (NULL == kcfg) + { + fprintf (stderr, + "Failed to load exchange configuration\n"); + return 1; + } + if ( (GNUNET_OK != exchange_signkeys_check ()) || + (GNUNET_OK != exchange_denomkeys_check ()) ) + { + GNUNET_CONFIGURATION_destroy (kcfg); + return 1; + } + GNUNET_CONFIGURATION_destroy (kcfg); + return 0; +} + +/* end of taler-exchange-keycheck.c */ diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c new file mode 100644 index 000000000..779e3a3d3 --- /dev/null +++ b/src/exchange-tools/taler-exchange-keyup.c @@ -0,0 +1,1039 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-keyup.c + * @brief Update the exchange's keys for coins and signatures, + * using the exchange's offline master key. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include <platform.h> +#include "taler_exchangedb_lib.h" + +/** + * When generating filenames from a cryptographic hash, we do not use + * all 512 bits but cut off after this number of characters (in + * base32-encoding). Base32 is 5 bit per character, and given that we + * have very few coin types we hash, at 100 bits the chance of + * collision (by accident over tiny set -- birthday paradox does not + * apply here!) is negligible. + */ +#define HASH_CUTOFF 20 + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Struct with all of the key information for a kind of coin. Hashed + * to generate a unique directory name per coin type. + */ +struct CoinTypeNBOP +{ + /** + * How long are the signatures legally valid? + */ + struct GNUNET_TIME_RelativeNBO duration_legal; + + /** + * How long can the coin be spend? + */ + struct GNUNET_TIME_RelativeNBO duration_spend; + + /** + * How long can the coin be withdrawn (generated)? + */ + struct GNUNET_TIME_RelativeNBO duration_withdraw; + + /** + * What is the value of the coin? + */ + struct TALER_AmountNBO value; + + /** + * What is the fee charged for withdrawl? + */ + struct TALER_AmountNBO fee_withdraw; + + /** + * What is the fee charged for deposits? + */ + struct TALER_AmountNBO fee_deposit; + + /** + * What is the fee charged for melting? + */ + struct TALER_AmountNBO fee_refresh; + + /** + * Key size in NBO. + */ + uint32_t rsa_keysize; +}; + +GNUNET_NETWORK_STRUCT_END + +/** + * Set of all of the parameters that chracterize a coin. + */ +struct CoinTypeParams +{ + + /** + * How long are the signatures legally valid? Should be + * significantly larger than @e duration_spend (i.e. years). + */ + struct GNUNET_TIME_Relative duration_legal; + + + /** + * How long can the coin be spend? Should be significantly + * larger than @e duration_withdraw (i.e. years). + */ + struct GNUNET_TIME_Relative duration_spend; + + /** + * How long can the coin be withdrawn (generated)? Should be small + * enough to limit how many coins will be signed into existence with + * the same key, but large enough to still provide a reasonable + * anonymity set. + */ + struct GNUNET_TIME_Relative duration_withdraw; + + /** + * How much should coin creation (@e duration_withdraw) duration + * overlap with the next coin? Basically, the starting time of two + * coins is always @e duration_withdraw - @e duration_overlap apart. + */ + struct GNUNET_TIME_Relative duration_overlap; + + /** + * What is the value of the coin? + */ + struct TALER_Amount value; + + /** + * What is the fee charged for withdrawl? + */ + struct TALER_Amount fee_withdraw; + + /** + * What is the fee charged for deposits? + */ + struct TALER_Amount fee_deposit; + + /** + * What is the fee charged for melting? + */ + struct TALER_Amount fee_refresh; + + /** + * Time at which this coin is supposed to become valid. + */ + struct GNUNET_TIME_Absolute anchor; + + /** + * Length of the RSA key in bits. + */ + uint32_t rsa_keysize; +}; + + +/** + * Filename of the master private key. + */ +static char *masterkeyfile; + +/** + * Filename where to write denomination key signing + * requests for the auditor (optional, can be NULL). + */ +static char *auditorrequestfile; + +/** + * Handle for writing the output for the auditor. + */ +static FILE *auditor_output_file; + +/** + * Director of the exchange, containing the keys. + */ +static char *exchange_directory; + +/** + * Time to pretend when the key update is executed. + */ +static char *pretend_time_str; + +/** + * Handle to the exchange's configuration + */ +static struct GNUNET_CONFIGURATION_Handle *kcfg; + +/** + * Time when the key update is executed. Either the actual current time, or a + * pretended time. + */ +static struct GNUNET_TIME_Absolute now; + +/** + * Master private key of the exchange. + */ +static struct TALER_MasterPrivateKeyP master_priv; + +/** + * Master public key of the exchange. + */ +static struct TALER_MasterPublicKeyP master_public_key; + +/** + * Until what time do we provide keys? + */ +static struct GNUNET_TIME_Absolute lookahead_sign_stamp; + + +/** + * Obtain the name of the directory we use to store signing + * keys created at time @a start. + * + * @param start time at which we create the signing key + * @return name of the directory we should use, basically "$EXCHANGEDIR/$TIME/"; + * (valid until next call to this function) + */ +static const char * +get_signkey_file (struct GNUNET_TIME_Absolute start) +{ + static char dir[4096]; + + GNUNET_snprintf (dir, + sizeof (dir), + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS DIR_SEPARATOR_STR "%llu", + exchange_directory, + (unsigned long long) start.abs_value_us); + return dir; +} + + +/** + * Hash the data defining the coin type. Exclude information that may + * not be the same for all instances of the coin type (i.e. the + * anchor, overlap). + * + * @param p coin parameters to convert to a hash + * @param[out] hash set to the hash matching @a p + */ +static void +hash_coin_type (const struct CoinTypeParams *p, + struct GNUNET_HashCode *hash) +{ + struct CoinTypeNBOP p_nbo; + + memset (&p_nbo, + 0, + sizeof (struct CoinTypeNBOP)); + p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend); + p_nbo.duration_legal = GNUNET_TIME_relative_hton (p->duration_legal); + p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw); + TALER_amount_hton (&p_nbo.value, + &p->value); + TALER_amount_hton (&p_nbo.fee_withdraw, + &p->fee_withdraw); + TALER_amount_hton (&p_nbo.fee_deposit, + &p->fee_deposit); + TALER_amount_hton (&p_nbo.fee_refresh, + &p->fee_refresh); + p_nbo.rsa_keysize = htonl (p->rsa_keysize); + GNUNET_CRYPTO_hash (&p_nbo, + sizeof (struct CoinTypeNBOP), + hash); +} + + +/** + * Obtain the name of the directory we should use to store coins of + * the given type. The directory name has the format + * "$EXCHANGEDIR/$VALUE/$HASH/" where "$VALUE" represents the value of the + * coin and "$HASH" encodes all of the coin's parameters, generating a + * unique string for each type of coin. Note that the "$HASH" + * includes neither the absolute creation time nor the key of the + * coin, thus the files in the subdirectory really just refer to the + * same type of coins, not the same coin. + * + * @param p coin parameters to convert to a directory name + * @return directory name (valid until next call to this function) + */ +static const char * +get_cointype_dir (const struct CoinTypeParams *p) +{ + static char dir[4096]; + struct GNUNET_HashCode hash; + char *hash_str; + char *val_str; + size_t i; + + hash_coin_type (p, &hash); + hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash, + sizeof (struct GNUNET_HashCode)); + GNUNET_assert (NULL != hash_str); + GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1); + hash_str[HASH_CUTOFF] = 0; + + val_str = TALER_amount_to_string (&p->value); + for (i = 0; i < strlen (val_str); i++) + if ( (':' == val_str[i]) || + ('.' == val_str[i]) ) + val_str[i] = '_'; + + GNUNET_snprintf (dir, + sizeof (dir), + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR "%s-%s", + exchange_directory, + val_str, + hash_str); + GNUNET_free (hash_str); + GNUNET_free (val_str); + return dir; +} + + +/** + * Obtain the name of the file we would use to store the key + * information for a coin of the given type @a p and validity + * start time @a start + * + * @param p parameters for the coin + * @param start when would the coin begin to be issued + * @return name of the file to use for this coin + * (valid until next call to this function) + */ +static const char * +get_cointype_file (const struct CoinTypeParams *p, + struct GNUNET_TIME_Absolute start) +{ + static char filename[4096]; + const char *dir; + + dir = get_cointype_dir (p); + GNUNET_snprintf (filename, + sizeof (filename), + "%s" DIR_SEPARATOR_STR "%llu", + dir, + (unsigned long long) start.abs_value_us); + return filename; +} + + +/** + * Get the latest key file from a past run of the key generation + * tool. Used to calculate the starting time for the keys we + * generate during this invocation. This function is used to + * handle both signing keys and coin keys, as in both cases + * the filenames correspond to the timestamps we need. + * + * @param cls closure, a `struct GNUNET_TIME_Absolute *`, updated + * to contain the highest timestamp (below #now) + * that was found + * @param filename complete filename (absolute path) + * @return #GNUNET_OK (to continue to iterate) + */ +static int +get_anchor_iter (void *cls, + const char *filename) +{ + struct GNUNET_TIME_Absolute *anchor = cls; + struct GNUNET_TIME_Absolute stamp; + const char *base; + char *end = NULL; + + base = GNUNET_STRINGS_get_short_name (filename); + stamp.abs_value_us = strtol (base, + &end, + 10); + if ((NULL == end) || (0 != *end)) + { + fprintf(stderr, + "Ignoring unexpected file `%s'.\n", + filename); + return GNUNET_OK; + } + *anchor = GNUNET_TIME_absolute_max (stamp, + *anchor); + return GNUNET_OK; +} + + +/** + * Get the timestamp where the first new key should be generated. + * Relies on correctly named key files (as we do not parse them, + * but just look at the filenames to "guess" at their contents). + * + * @param dir directory that should contain the existing keys + * @param duration how long is one key valid (for signing)? + * @param overlap what's the overlap between the keys validity period? + * @param[out] anchor the timestamp where the first new key should be generated + */ +static void +get_anchor (const char *dir, + struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Relative overlap, + struct GNUNET_TIME_Absolute *anchor) +{ + GNUNET_assert (0 == duration.rel_value_us % 1000000); + GNUNET_assert (0 == overlap.rel_value_us % 1000000); + if (GNUNET_YES != + GNUNET_DISK_directory_test (dir, + GNUNET_YES)) + { + *anchor = now; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No existing keys found, starting with fresh key set.\n"); + return; + } + *anchor = GNUNET_TIME_UNIT_ZERO_ABS; + if (-1 == + GNUNET_DISK_directory_scan (dir, + &get_anchor_iter, + anchor)) + { + *anchor = now; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No existing keys found, starting with fresh key set.\n"); + return; + } + + if ((GNUNET_TIME_absolute_add (*anchor, + duration)).abs_value_us < now.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Existing keys are way too old, starting with fresh key set.\n"); + *anchor = now; + } + else if (anchor->abs_value_us != now.abs_value_us) + { + /* Real starting time is the last start time + duration - overlap */ + *anchor = GNUNET_TIME_absolute_add (*anchor, + duration); + *anchor = GNUNET_TIME_absolute_subtract (*anchor, + overlap); + } + /* anchor is now the stamp where we need to create a new key */ +} + + +/** + * Create a exchange signing key (for signing exchange messages, not for coins) + * and assert its correctness by signing it with the master key. + * + * @param start start time of the validity period for the key + * @param duration how long should the key be valid + * @param end when do all signatures by this key expire + * @param[out] pi set to the signing key information + */ +static void +create_signkey_issue_priv (struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Absolute end, + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *pi) +{ + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct TALER_ExchangeSigningKeyValidityPS *issue = &pi->issue; + + priv = GNUNET_CRYPTO_eddsa_key_create (); + pi->signkey_priv.eddsa_priv = *priv; + GNUNET_free (priv); + issue->master_public_key = master_public_key; + issue->start = GNUNET_TIME_absolute_hton (start); + issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start, + duration)); + issue->end = GNUNET_TIME_absolute_hton (end); + GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv, + &issue->signkey_pub.eddsa_pub); + issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); + issue->purpose.size = htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS) - + offsetof (struct TALER_ExchangeSigningKeyValidityPS, + purpose)); + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv, + &issue->purpose, + &issue->signature.eddsa_signature)); +} + + +/** + * Generate signing keys starting from the last key found to + * the lookahead time. + * + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +exchange_keys_update_signkeys () +{ + struct GNUNET_TIME_Relative signkey_duration; + struct GNUNET_TIME_Relative legal_duration; + struct GNUNET_TIME_Absolute anchor; + char *signkey_dir; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + "exchange_keys", + "signkey_duration", + &signkey_duration)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "signkey_duration"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + "exchange_keys", + "legal_duration", + &legal_duration)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "legal_duration", + "fails to specify valid timeframe"); + return GNUNET_SYSERR; + } + if (signkey_duration.rel_value_us > legal_duration.rel_value_us) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "legal_duration", + "must be longer than signkey_duration"); + return GNUNET_SYSERR; + } + TALER_round_rel_time (&signkey_duration); + GNUNET_asprintf (&signkey_dir, + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS, + exchange_directory); + /* make sure the directory exists */ + if (GNUNET_OK != + GNUNET_DISK_directory_create (signkey_dir)) + { + fprintf (stderr, + "Failed to create signing key directory\n"); + return GNUNET_SYSERR; + } + + get_anchor (signkey_dir, + signkey_duration, + GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */, + &anchor); + + while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) + { + const char *skf; + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP signkey_issue; + ssize_t nwrite; + struct GNUNET_TIME_Absolute end; + + skf = get_signkey_file (anchor); + end = GNUNET_TIME_absolute_add (anchor, + legal_duration); + GNUNET_break (GNUNET_YES != + GNUNET_DISK_file_test (skf)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Generating signing key for %s.\n", + GNUNET_STRINGS_absolute_time_to_string (anchor)); + create_signkey_issue_priv (anchor, + signkey_duration, + end, + &signkey_issue); + nwrite = GNUNET_DISK_fn_write (skf, + &signkey_issue, + sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP), + GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); + if (sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP) != nwrite) + { + fprintf (stderr, + "Failed to write to file `%s': %s\n", + skf, + STRERROR (errno)); + return GNUNET_SYSERR; + } + anchor = GNUNET_TIME_absolute_add (anchor, + signkey_duration); + } + return GNUNET_OK; +} + + +/** + * Parse configuration for coin type parameters. Also determines + * our anchor by looking at the existing coins of the same type. + * + * @param ct section in the configuration file giving the coin type parameters + * @param[out] params set to the coin parameters from the configuration + * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid + */ +static int +get_cointype_params (const char *ct, + struct CoinTypeParams *params) +{ + const char *dir; + unsigned long long rsa_keysize; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + ct, + "duration_withdraw", + ¶ms->duration_withdraw)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + ct, + "duration_withdraw"); + return GNUNET_SYSERR; + } + TALER_round_rel_time (¶ms->duration_withdraw); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + ct, + "duration_spend", + ¶ms->duration_spend)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + ct, + "duration_spend"); + return GNUNET_SYSERR; + } + TALER_round_rel_time (¶ms->duration_spend); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + ct, + "duration_legal", + ¶ms->duration_legal)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + ct, + "duration_legal"); + return GNUNET_SYSERR; + } + TALER_round_rel_time (¶ms->duration_legal); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + ct, + "duration_overlap", + ¶ms->duration_overlap)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + ct, + "exchange_denom_duration_overlap"); + return GNUNET_SYSERR; + } + TALER_round_rel_time (¶ms->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", + ¶ms->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", + ¶ms->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", + ¶ms->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", + ¶ms->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, + ¶ms->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, + ¶ms->value); + TALER_amount_hton (&dki->issue.properties.fee_withdraw, + ¶ms->fee_withdraw); + TALER_amount_hton (&dki->issue.properties.fee_deposit, + ¶ms->fee_deposit); + TALER_amount_hton (&dki->issue.properties.fee_refresh, + ¶ms->fee_refresh); + dki->issue.properties.purpose.purpose + = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); + dki->issue.properties.purpose.size + = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv, + &dki->issue.properties.purpose, + &dki->issue.signature.eddsa_signature)); +} + + +/** + * Generate new coin signing keys for the coin type of the given @a + * coin_alias. + * + * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure + * @param coin_alias name of the coin's section in the configuration + */ +static void +exchange_keys_update_cointype (void *cls, + const char *coin_alias) +{ + int *ret = cls; + struct CoinTypeParams p; + const char *dkf; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation denomkey_issue; + + if (0 != strncasecmp (coin_alias, + "coin_", + strlen ("coin_"))) + return; /* not a coin definition */ + if (GNUNET_OK != + get_cointype_params (coin_alias, + &p)) + { + *ret = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + GNUNET_DISK_directory_create (get_cointype_dir (&p))) + { + *ret = GNUNET_SYSERR; + return; + } + + while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) + { + dkf = get_cointype_file (&p, + p.anchor); + GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Generating denomination key for type `%s', start %s at %s\n", + coin_alias, + GNUNET_STRINGS_absolute_time_to_string (p.anchor), + dkf); + create_denomkey_issue (&p, + &denomkey_issue); + if (GNUNET_OK != + TALER_EXCHANGEDB_denomination_key_write (dkf, + &denomkey_issue)) + { + fprintf (stderr, + "Failed to write denomination key information to file `%s'.\n", + dkf); + *ret = GNUNET_SYSERR; + GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); + return; + } + if ( (NULL != auditor_output_file) && + (sizeof (denomkey_issue.issue.properties) != + fwrite (&denomkey_issue.issue.properties, + sizeof (struct TALER_DenominationKeyValidityPS), + 1, + auditor_output_file)) ) + { + fprintf (stderr, + "Failed to write denomination key information to %s: %s\n", + auditorrequestfile, + STRERROR (errno)); + *ret = GNUNET_SYSERR; + return; + } + GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); + p.anchor = GNUNET_TIME_absolute_add (p.anchor, + p.duration_spend); + p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, + p.duration_overlap); + } +} + + +/** + * Update all of the denomination keys of the exchange. + * + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +exchange_keys_update_denomkeys () +{ + int ok; + + ok = GNUNET_OK; + GNUNET_CONFIGURATION_iterate_sections (kcfg, + &exchange_keys_update_cointype, + &ok); + return ok; +} + + +/** + * The main function of the taler-exchange-keyup tool. This tool is used + * to create the signing and denomination keys for the exchange. It uses + * the long-term offline private key and writes the (additional) key + * files to the respective exchange directory (from where they can then be + * copied to the online server). Note that we need (at least) the + * most recent generated previous keys so as to align the validity + * periods. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'d', "exchange-dir", "DIR", + "exchange directory with keys to update", 1, + &GNUNET_GETOPT_set_filename, &exchange_directory}, + TALER_GETOPT_OPTION_HELP ("Setup signing and denomination keys for a Taler exchange"), + {'m', "master-key", "FILE", + "master key file (private key)", 1, + &GNUNET_GETOPT_set_filename, &masterkeyfile}, + {'o', "output", "FILE", + "auditor denomination key signing request file to create", 1, + &GNUNET_GETOPT_set_filename, &auditorrequestfile}, + {'t', "time", "TIMESTAMP", + "pretend it is a different time for the update", 0, + &GNUNET_GETOPT_set_string, &pretend_time_str}, + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_TIME_Relative lookahead_sign; + struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-keyup", + "WARNING", + NULL)); + + if (GNUNET_GETOPT_run ("taler-exchange-keyup", + options, + argc, argv) < 0) + return 1; + if (NULL == exchange_directory) + { + fprintf (stderr, + "Exchange directory not given\n"); + return 1; + } + if (NULL != pretend_time_str) + { + if (GNUNET_OK != + GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, + &now)) + { + fprintf (stderr, + "timestamp `%s' invalid\n", + pretend_time_str); + return 1; + } + } + else + { + now = GNUNET_TIME_absolute_get (); + } + TALER_round_abs_time (&now); + + kcfg = TALER_config_load (exchange_directory); + if (NULL == kcfg) + { + fprintf (stderr, + "Failed to load exchange configuration\n"); + return 1; + } + if (NULL == masterkeyfile) + { + fprintf (stderr, + "Master key file not given\n"); + return 1; + } + eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); + if (NULL == eddsa_priv) + { + fprintf (stderr, + "Failed to initialize master key from file `%s'\n", + masterkeyfile); + return 1; + } + master_priv.eddsa_priv = *eddsa_priv; + GNUNET_free (eddsa_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv, + &master_public_key.eddsa_pub); + + if (NULL != auditorrequestfile) + { + auditor_output_file = FOPEN (auditorrequestfile, + "w"); + if (NULL == auditor_output_file) + { + fprintf (stderr, + "Failed to open `%s' for writing: %s\n", + auditorrequestfile, + STRERROR (errno)); + return 1; + } + } + + /* check if key from file matches the one from the configuration */ + { + struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_data (kcfg, + "exchange", + "master_public_key", + &master_public_key_from_cfg, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "master_public_key"); + return 1; + } + if (0 != + memcmp (&master_public_key, + &master_public_key_from_cfg, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "master_public_key", + _("does not match with private key")); + return 1; + } + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + "exchange_keys", + "lookahead_sign", + &lookahead_sign)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "lookahead_sign"); + return GNUNET_SYSERR; + } + if (0 == lookahead_sign.rel_value_us) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "lookahead_sign", + _("must not be zero")); + return GNUNET_SYSERR; + } + TALER_round_rel_time (&lookahead_sign); + lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, + lookahead_sign); + + + /* finally, do actual work */ + if (GNUNET_OK != exchange_keys_update_signkeys ()) + return 1; + + if (GNUNET_OK != exchange_keys_update_denomkeys ()) + return 1; + if (NULL != auditor_output_file) + { + FCLOSE (auditor_output_file); + auditor_output_file = NULL; + } + return 0; +} + +/* end of taler-exchange-keyup.c */ diff --git a/src/exchange-tools/taler-exchange-reservemod.c b/src/exchange-tools/taler-exchange-reservemod.c new file mode 100644 index 000000000..984b7f8ee --- /dev/null +++ b/src/exchange-tools/taler-exchange-reservemod.c @@ -0,0 +1,206 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-reservemod.c + * @brief Modify reserves. Allows manipulation of reserve balances. + * @author Florian Dold + * @author Benedikt Mueller + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <libpq-fe.h> +#include <jansson.h> +#include "taler_exchangedb_plugin.h" + +/** + * Director of the exchange, containing the keys. + */ +static char *exchange_directory; + +/** + * Handle to the exchange's configuration + */ +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Our DB plugin. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; + + +/** + * The main function of the reservemod tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + char *reserve_pub_str = NULL; + char *add_str = NULL; + struct TALER_Amount add_value; + char *details = NULL; + json_t *jdetails; + json_error_t error; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_EXCHANGEDB_Session *session; + const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'a', "add", "DENOM", + "value to add", 1, + &GNUNET_GETOPT_set_string, &add_str}, + {'d', "exchange-dir", "DIR", + "exchange directory with keys to update", 1, + &GNUNET_GETOPT_set_filename, &exchange_directory}, + {'D', "details", "JSON", + "details about the bank transaction which justify why we add this amount", 1, + &GNUNET_GETOPT_set_string, &details}, + TALER_GETOPT_OPTION_HELP ("Deposit funds into a Taler reserve"), + {'R', "reserve", "KEY", + "reserve (public key) to modify", 1, + &GNUNET_GETOPT_set_string, &reserve_pub_str}, + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + int ret; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-reservemod", + "WARNING", + NULL)); + + if (GNUNET_GETOPT_run ("taler-exchange-reservemod", + options, + argc, argv) < 0) + return 1; + if (NULL == exchange_directory) + { + fprintf (stderr, + "Exchange directory not given\n"); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (details); + GNUNET_free_non_null (reserve_pub_str); + return 1; + } + if ((NULL == reserve_pub_str) || + (GNUNET_OK != + GNUNET_STRINGS_string_to_data (reserve_pub_str, + strlen (reserve_pub_str), + &reserve_pub, + sizeof (struct TALER_ReservePublicKeyP)))) + { + fprintf (stderr, + "Parsing reserve key invalid\n"); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (details); + GNUNET_free_non_null (reserve_pub_str); + return 1; + } + if ( (NULL == add_str) || + (GNUNET_OK != + TALER_string_to_amount (add_str, + &add_value)) ) + { + fprintf (stderr, + "Failed to parse currency amount `%s'\n", + add_str); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (details); + GNUNET_free_non_null (reserve_pub_str); + return 1; + } + + if (NULL == details) + { + fprintf (stderr, + "No wiring details given (justification required)\n"); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (reserve_pub_str); + return 1; + } + + cfg = TALER_config_load (exchange_directory); + if (NULL == cfg) + { + fprintf (stderr, + "Failed to load exchange configuration\n"); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (details); + GNUNET_free_non_null (reserve_pub_str); + return 1; + } + ret = 1; + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + fprintf (stderr, + "Failed to initialize database plugin.\n"); + goto cleanup; + } + + session = plugin->get_session (plugin->cls, + GNUNET_NO); + if (NULL == session) + { + fprintf (stderr, + "Failed to initialize DB session\n"); + goto cleanup; + } + jdetails = json_loads (details, + JSON_REJECT_DUPLICATES, + &error); + if (NULL == jdetails) + { + fprintf (stderr, + "Failed to parse JSON transaction details `%s': %s (%s)\n", + details, + error.text, + error.source); + goto cleanup; + } + /* FIXME: maybe allow passing timestamp via command-line? */ + ret = plugin->reserves_in_insert (plugin->cls, + session, + &reserve_pub, + &add_value, + GNUNET_TIME_absolute_get (), + jdetails); + json_decref (jdetails); + if (GNUNET_SYSERR == ret) + { + fprintf (stderr, + "Failed to update reserve.\n"); + goto cleanup; + } + if (GNUNET_NO == ret) + { + fprintf (stderr, + "Record exists, reserve not updated.\n"); + } + ret = 0; + cleanup: + if (NULL != plugin) + TALER_EXCHANGEDB_plugin_unload (plugin); + if (NULL != cfg) + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free_non_null (add_str); + GNUNET_free_non_null (details); + GNUNET_free_non_null (reserve_pub_str); + return ret; +} + +/* end taler-exchange-reservemod.c */ diff --git a/src/exchange-tools/taler-exchange-sepa.c b/src/exchange-tools/taler-exchange-sepa.c new file mode 100644 index 000000000..a3ac95436 --- /dev/null +++ b/src/exchange-tools/taler-exchange-sepa.c @@ -0,0 +1,163 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-sepa.c + * @brief Create signed response for /wire/sepa requests. + * @author Christian Grothoff + */ +#include <platform.h> +#include <jansson.h> +#include "taler_crypto_lib.h" +#include "taler_signatures.h" + + +/** + * Filename of the master private key. + */ +static char *masterkeyfile; + +/** + * Account holder name. + */ +static char *sepa_name; + +/** + * IBAN number. + */ +static char *iban; + +/** + * BIC number. + */ +static char *bic; + +/** + * Where to write the result. + */ +static char *output_filename; + + +/** + * The main function of the taler-exchange-sepa tool. This tool is used + * to sign the SEPA bank account details using the master key. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'b', "bic", "BICCODE", + "bank BIC code", 1, + &GNUNET_GETOPT_set_string, &bic}, + {'i', "iban", "IBAN", + "IBAN number of the account", 1, + &GNUNET_GETOPT_set_string, &iban}, + {'m', "master-key", "FILE", + "master key file (private key)", 1, + &GNUNET_GETOPT_set_filename, &masterkeyfile}, + {'n', "name", "NAME", + "name of the account holder", 1, + &GNUNET_GETOPT_set_string, &sepa_name}, + {'o', "output", "FILE", + "where to write the result", 1, + &GNUNET_GETOPT_set_filename, &output_filename}, + TALER_GETOPT_OPTION_HELP ("Setup /wire/sepa response"), + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; + struct TALER_MasterWireSepaDetailsPS wsd; + struct TALER_MasterSignatureP sig; + struct GNUNET_HashContext *hc; + json_t *reply; + char *json_str; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-sepa", + "WARNING", + NULL)); + + if (GNUNET_GETOPT_run ("taler-exchange-sepa", + options, + argc, argv) < 0) + return 1; + if (NULL == masterkeyfile) + { + fprintf (stderr, + "Master key file not given\n"); + return 1; + } + eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); + if (NULL == eddsa_priv) + { + fprintf (stderr, + "Failed to initialize master key from file `%s'\n", + masterkeyfile); + return 1; + } + + /* Compute message to sign */ + hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + sepa_name, + strlen (sepa_name) + 1); + GNUNET_CRYPTO_hash_context_read (hc, + iban, + strlen (iban) + 1); + GNUNET_CRYPTO_hash_context_read (hc, + bic, + strlen (bic) + 1); + wsd.purpose.size = htonl (sizeof (wsd)); + wsd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); + GNUNET_CRYPTO_hash_context_finish (hc, + &wsd.h_sepa_details); + GNUNET_CRYPTO_eddsa_sign (eddsa_priv, + &wsd.purpose, + &sig.eddsa_signature); + GNUNET_free (eddsa_priv); + + /* build JSON message */ + reply = json_pack ("{s:s, s:s, s:s, s:o}", + "receiver_name", sepa_name, + "iban", iban, + "bic", bic, + "sig", TALER_json_from_data (&sig, + sizeof (sig))); + GNUNET_assert (NULL != reply); + + /* dump result to stdout */ + json_str = json_dumps (reply, JSON_INDENT(2)); + GNUNET_assert (NULL != json_str); + + if (NULL != output_filename) + { + fclose (stdout); + stdout = fopen (output_filename, + "w+"); + } + fprintf (stdout, + "%s", + json_str); + fflush (stdout); + free (json_str); + return 0; +} + +/* end of taler-exchange-sepa.c */ diff --git a/src/exchange/.gitignore b/src/exchange/.gitignore new file mode 100644 index 000000000..a1e5e9aa7 --- /dev/null +++ b/src/exchange/.gitignore @@ -0,0 +1,6 @@ +taler-exchange-dbinit +taler-exchange-keycheck +taler-exchange-keyup +taler-exchange-pursemod +taler-exchange-reservemod +taler-exchange-httpd
\ No newline at end of file diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am new file mode 100644 index 000000000..443ac511a --- /dev/null +++ b/src/exchange/Makefile.am @@ -0,0 +1,59 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +bin_PROGRAMS = \ + taler-exchange-aggregator \ + taler-exchange-httpd + +taler_exchange_aggregator_SOURCES = \ + taler-exchange-aggregator.c +taler_exchange_aggregator_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/wire/libtalerwire.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -ljansson \ + -lgnunetutil + +taler_exchange_httpd_SOURCES = \ + taler-exchange-httpd.c taler-exchange-httpd.h \ + taler-exchange-httpd_admin.c taler-exchange-httpd_admin.h \ + taler-exchange-httpd_db.c taler-exchange-httpd_db.h \ + taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \ + taler-exchange-httpd_keystate.c taler-exchange-httpd_keystate.h \ + taler-exchange-httpd_mhd.c taler-exchange-httpd_mhd.h \ + taler-exchange-httpd_parsing.c taler-exchange-httpd_parsing.h \ + taler-exchange-httpd_refresh.c taler-exchange-httpd_refresh.h \ + taler-exchange-httpd_reserve.c taler-exchange-httpd_reserve.h \ + taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \ + taler-exchange-httpd_tracking.c taler-exchange-httpd_tracking.h \ + taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \ + taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h +taler_exchange_httpd_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + -lmicrohttpd \ + -ljansson \ + -lgnunetutil \ + -lpthread + +if HAVE_DEVELOPER +taler_exchange_httpd_SOURCES += \ + taler-exchange-httpd_test.c taler-exchange-httpd_test.h +endif + +check_SCRIPTS = \ + test_taler_exchange_httpd.sh + +if HAVE_EXPENSIVE_TESTS +check_SCRIPTS += \ + test_taler_exchange_httpd_afl.sh +endif + +TESTS = $(check_SCRIPTS) diff --git a/src/mint/afl-tests/id:000000,orig:admin_add_incoming.req b/src/exchange/afl-tests/id:000000,orig:admin_add_incoming.req index 677678b5d..677678b5d 100644 --- a/src/mint/afl-tests/id:000000,orig:admin_add_incoming.req +++ b/src/exchange/afl-tests/id:000000,orig:admin_add_incoming.req diff --git a/src/mint/afl-tests/id:000001,orig:deposit.req b/src/exchange/afl-tests/id:000001,orig:deposit.req index ec490759e..ec490759e 100644 --- a/src/mint/afl-tests/id:000001,orig:deposit.req +++ b/src/exchange/afl-tests/id:000001,orig:deposit.req diff --git a/src/mint/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 b/src/exchange/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 index 6f317bf51..6f317bf51 100644 --- a/src/mint/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 +++ b/src/exchange/afl-tests/id:000001,sig:06,src:000004,op:flip1,pos:21060 diff --git a/src/mint/afl-tests/id:000002,orig:keys.req b/src/exchange/afl-tests/id:000002,orig:keys.req index a9503a864..a9503a864 100644 --- a/src/mint/afl-tests/id:000002,orig:keys.req +++ b/src/exchange/afl-tests/id:000002,orig:keys.req diff --git a/src/mint/afl-tests/id:000003,orig:refresh_link.req b/src/exchange/afl-tests/id:000003,orig:refresh_link.req index acf3dff51..acf3dff51 100644 --- a/src/mint/afl-tests/id:000003,orig:refresh_link.req +++ b/src/exchange/afl-tests/id:000003,orig:refresh_link.req diff --git a/src/mint/afl-tests/id:000004,orig:refresh_melt.req b/src/exchange/afl-tests/id:000004,orig:refresh_melt.req index 98b5b6389..98b5b6389 100644 --- a/src/mint/afl-tests/id:000004,orig:refresh_melt.req +++ b/src/exchange/afl-tests/id:000004,orig:refresh_melt.req diff --git a/src/mint/afl-tests/id:000005,orig:refresh_reveal.req b/src/exchange/afl-tests/id:000005,orig:refresh_reveal.req index 3fb143960..3fb143960 100644 --- a/src/mint/afl-tests/id:000005,orig:refresh_reveal.req +++ b/src/exchange/afl-tests/id:000005,orig:refresh_reveal.req diff --git a/src/mint/afl-tests/id:000006,orig:reserve_status.req b/src/exchange/afl-tests/id:000006,orig:reserve_status.req index 4f988f669..4f988f669 100644 --- a/src/mint/afl-tests/id:000006,orig:reserve_status.req +++ b/src/exchange/afl-tests/id:000006,orig:reserve_status.req diff --git a/src/mint/afl-tests/id:000007,orig:reserve_withdraw.req b/src/exchange/afl-tests/id:000007,orig:reserve_withdraw.req index 484950250..484950250 100644 --- a/src/mint/afl-tests/id:000007,orig:reserve_withdraw.req +++ b/src/exchange/afl-tests/id:000007,orig:reserve_withdraw.req diff --git a/src/mint/afl-tests/id:000008,orig:wire.req b/src/exchange/afl-tests/id:000008,orig:wire.req index a4f1d0749..a4f1d0749 100644 --- a/src/mint/afl-tests/id:000008,orig:wire.req +++ b/src/exchange/afl-tests/id:000008,orig:wire.req diff --git a/src/mint/afl-tests/id:000009,orig:wire_sepa.req b/src/exchange/afl-tests/id:000009,orig:wire_sepa.req index 80d3d4619..80d3d4619 100644 --- a/src/mint/afl-tests/id:000009,orig:wire_sepa.req +++ b/src/exchange/afl-tests/id:000009,orig:wire_sepa.req diff --git a/src/mint/afl-tests/id:000010,orig:wire_test.req b/src/exchange/afl-tests/id:000010,orig:wire_test.req index 684352c96..684352c96 100644 --- a/src/mint/afl-tests/id:000010,orig:wire_test.req +++ b/src/exchange/afl-tests/id:000010,orig:wire_test.req diff --git a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov index 4cb4552ad..4cb4552ad 100644 --- a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov +++ b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:1,+cov diff --git a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov index ffb59d7f9..ffb59d7f9 100644 --- a/src/mint/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov +++ b/src/exchange/afl-tests/id:000011,src:000000,op:flip1,pos:2,+cov diff --git a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov index 801bf114d..801bf114d 100644 --- a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov +++ b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:3,+cov diff --git a/src/mint/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov b/src/exchange/afl-tests/id:000012,src:000000,op:flip1,pos:4,+cov Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 diff --git a/src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov b/src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov index 65cd9fc29..65cd9fc29 100644 --- a/src/mint/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov +++ b/src/exchange/afl-tests/id:001051,src:000004,op:flip1,pos:55,+cov diff --git a/src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59 b/src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59 index 22f1df82e..22f1df82e 100644 --- a/src/mint/afl-tests/id:001052,src:000004,op:flip1,pos:59 +++ b/src/exchange/afl-tests/id:001052,src:000004,op:flip1,pos:59 diff --git a/src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov b/src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov index ce06ef765..ce06ef765 100644 --- a/src/mint/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov +++ b/src/exchange/afl-tests/id:001053,src:000004,op:flip1,pos:87,+cov diff --git a/src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89 b/src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89 index b09891805..b09891805 100644 --- a/src/mint/afl-tests/id:001054,src:000004,op:flip1,pos:89 +++ b/src/exchange/afl-tests/id:001054,src:000004,op:flip1,pos:89 diff --git a/src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov b/src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov index 337ece077..337ece077 100644 --- a/src/mint/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov +++ b/src/exchange/afl-tests/id:001055,src:000004,op:flip1,pos:106,+cov diff --git a/src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108 b/src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108 index 5b908c709..5b908c709 100644 --- a/src/mint/afl-tests/id:001056,src:000004,op:flip1,pos:108 +++ b/src/exchange/afl-tests/id:001056,src:000004,op:flip1,pos:108 diff --git a/src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108 b/src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108 index 340414e5d..340414e5d 100644 --- a/src/mint/afl-tests/id:001057,src:000004,op:flip1,pos:108 +++ b/src/exchange/afl-tests/id:001057,src:000004,op:flip1,pos:108 diff --git a/src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110 b/src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110 index 77f342a2d..77f342a2d 100644 --- a/src/mint/afl-tests/id:001058,src:000004,op:flip1,pos:110 +++ b/src/exchange/afl-tests/id:001058,src:000004,op:flip1,pos:110 diff --git a/src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov b/src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov index 1f1c1c903..1f1c1c903 100644 --- a/src/mint/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov +++ b/src/exchange/afl-tests/id:001059,src:000004,op:flip1,pos:111,+cov diff --git a/src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112 b/src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112 index 877f3c6f2..877f3c6f2 100644 --- a/src/mint/afl-tests/id:001060,src:000004,op:flip1,pos:112 +++ b/src/exchange/afl-tests/id:001060,src:000004,op:flip1,pos:112 diff --git a/src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov b/src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov index 30c8d756e..30c8d756e 100644 --- a/src/mint/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov +++ b/src/exchange/afl-tests/id:001061,src:000004,op:flip1,pos:134,+cov diff --git a/src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov b/src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov index d70e2f137..d70e2f137 100644 --- a/src/mint/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov +++ b/src/exchange/afl-tests/id:001062,src:000004,op:flip1,pos:138,+cov diff --git a/src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov b/src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov index 05c492917..05c492917 100644 --- a/src/mint/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov +++ b/src/exchange/afl-tests/id:001063,src:000004,op:flip1,pos:152,+cov diff --git a/src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov b/src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov index 9a4afa514..9a4afa514 100644 --- a/src/mint/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov +++ b/src/exchange/afl-tests/id:001064,src:000004,op:flip1,pos:154,+cov diff --git a/src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov b/src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov index cf3ab362e..cf3ab362e 100644 --- a/src/mint/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov +++ b/src/exchange/afl-tests/id:001065,src:000004,op:flip1,pos:475,+cov diff --git a/src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov b/src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov index 3957890d9..3957890d9 100644 --- a/src/mint/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov +++ b/src/exchange/afl-tests/id:001066,src:000004,op:flip1,pos:651,+cov diff --git a/src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov b/src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov index 0fc87d10b..0fc87d10b 100644 --- a/src/mint/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov +++ b/src/exchange/afl-tests/id:001067,src:000004,op:flip1,pos:783,+cov diff --git a/src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150 b/src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150 index 695b545cb..695b545cb 100644 --- a/src/mint/afl-tests/id:001068,src:000004,op:flip1,pos:1150 +++ b/src/exchange/afl-tests/id:001068,src:000004,op:flip1,pos:1150 diff --git a/src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov b/src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov index 38455bb28..38455bb28 100644 --- a/src/mint/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov +++ b/src/exchange/afl-tests/id:001069,src:000004,op:flip1,pos:1278,+cov diff --git a/src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649 b/src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649 index 310494eff..310494eff 100644 --- a/src/mint/afl-tests/id:001070,src:000004,op:flip1,pos:1649 +++ b/src/exchange/afl-tests/id:001070,src:000004,op:flip1,pos:1649 diff --git a/src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov b/src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov index 6bedb8dc7..6bedb8dc7 100644 --- a/src/mint/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov +++ b/src/exchange/afl-tests/id:001071,src:000004,op:flip1,pos:1662,+cov diff --git a/src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148 b/src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148 index b18620069..b18620069 100644 --- a/src/mint/afl-tests/id:001072,src:000004,op:flip1,pos:2148 +++ b/src/exchange/afl-tests/id:001072,src:000004,op:flip1,pos:2148 diff --git a/src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov b/src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov index d0b7b7bfe..d0b7b7bfe 100644 --- a/src/mint/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov +++ b/src/exchange/afl-tests/id:001073,src:000004,op:flip1,pos:2437,+cov diff --git a/src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647 b/src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647 index 1d9852284..1d9852284 100644 --- a/src/mint/afl-tests/id:001074,src:000004,op:flip1,pos:2647 +++ b/src/exchange/afl-tests/id:001074,src:000004,op:flip1,pos:2647 diff --git a/src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146 b/src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146 index 1035c4053..1035c4053 100644 --- a/src/mint/afl-tests/id:001075,src:000004,op:flip1,pos:3146 +++ b/src/exchange/afl-tests/id:001075,src:000004,op:flip1,pos:3146 diff --git a/src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov b/src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov index 63edd3a7c..63edd3a7c 100644 --- a/src/mint/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov +++ b/src/exchange/afl-tests/id:001076,src:000004,op:flip1,pos:3205,+cov diff --git a/src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645 b/src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645 index d404fd872..d404fd872 100644 --- a/src/mint/afl-tests/id:001077,src:000004,op:flip1,pos:3645 +++ b/src/exchange/afl-tests/id:001077,src:000004,op:flip1,pos:3645 diff --git a/src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov b/src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov index e93f23838..e93f23838 100644 --- a/src/mint/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov +++ b/src/exchange/afl-tests/id:001078,src:000004,op:flip1,pos:3980,+cov diff --git a/src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144 b/src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144 index 7d1b205dc..7d1b205dc 100644 --- a/src/mint/afl-tests/id:001079,src:000004,op:flip1,pos:4144 +++ b/src/exchange/afl-tests/id:001079,src:000004,op:flip1,pos:4144 diff --git a/src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov b/src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov index 75827a87c..75827a87c 100644 --- a/src/mint/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov +++ b/src/exchange/afl-tests/id:001080,src:000004,op:flip1,pos:4198,+cov diff --git a/src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov b/src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov index 1a7dcd0eb..1a7dcd0eb 100644 --- a/src/mint/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov +++ b/src/exchange/afl-tests/id:001081,src:000004,op:flip1,pos:4249,+cov diff --git a/src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov b/src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov index 42705b2be..42705b2be 100644 --- a/src/mint/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov +++ b/src/exchange/afl-tests/id:001082,src:000004,op:flip1,pos:4291,+cov diff --git a/src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov b/src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov index 1c7d16a8b..1c7d16a8b 100644 --- a/src/mint/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov +++ b/src/exchange/afl-tests/id:001083,src:000004,op:flip1,pos:4673,+cov diff --git a/src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov b/src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov index 98e29de85..98e29de85 100644 --- a/src/mint/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov +++ b/src/exchange/afl-tests/id:001084,src:000004,op:flip1,pos:5206,+cov diff --git a/src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov b/src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov index 1afbaeb36..1afbaeb36 100644 --- a/src/mint/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov +++ b/src/exchange/afl-tests/id:001085,src:000004,op:flip1,pos:5361,+cov diff --git a/src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362 b/src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362 index 853498b32..853498b32 100644 --- a/src/mint/afl-tests/id:001086,src:000004,op:flip1,pos:5362 +++ b/src/exchange/afl-tests/id:001086,src:000004,op:flip1,pos:5362 diff --git a/src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov b/src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov index 5b859f6a5..5b859f6a5 100644 --- a/src/mint/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov +++ b/src/exchange/afl-tests/id:001087,src:000004,op:flip1,pos:5507,+cov diff --git a/src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639 b/src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639 index c30ed6671..c30ed6671 100644 --- a/src/mint/afl-tests/id:001088,src:000004,op:flip1,pos:6639 +++ b/src/exchange/afl-tests/id:001088,src:000004,op:flip1,pos:6639 diff --git a/src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138 b/src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138 index c05262a60..c05262a60 100644 --- a/src/mint/afl-tests/id:001089,src:000004,op:flip1,pos:7138 +++ b/src/exchange/afl-tests/id:001089,src:000004,op:flip1,pos:7138 diff --git a/src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov b/src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov index f5c311ccb..f5c311ccb 100644 --- a/src/mint/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov +++ b/src/exchange/afl-tests/id:001090,src:000004,op:flip1,pos:8027,+cov diff --git a/src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136 b/src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136 index 63c68a5b1..63c68a5b1 100644 --- a/src/mint/afl-tests/id:001091,src:000004,op:flip1,pos:8136 +++ b/src/exchange/afl-tests/id:001091,src:000004,op:flip1,pos:8136 diff --git a/src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636 b/src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636 index ed3eb4a01..ed3eb4a01 100644 --- a/src/mint/afl-tests/id:001092,src:000004,op:flip1,pos:8636 +++ b/src/exchange/afl-tests/id:001092,src:000004,op:flip1,pos:8636 diff --git a/src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov b/src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov index 32cd75712..32cd75712 100644 --- a/src/mint/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov +++ b/src/exchange/afl-tests/id:001093,src:000004,op:flip1,pos:8655,+cov diff --git a/src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712 b/src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712 index dd97c6ac7..dd97c6ac7 100644 --- a/src/mint/afl-tests/id:001094,src:000004,op:flip1,pos:8712 +++ b/src/exchange/afl-tests/id:001094,src:000004,op:flip1,pos:8712 diff --git a/src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768 b/src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768 index 7ef20f5f7..7ef20f5f7 100644 --- a/src/mint/afl-tests/id:001095,src:000004,op:flip1,pos:8768 +++ b/src/exchange/afl-tests/id:001095,src:000004,op:flip1,pos:8768 diff --git a/src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825 b/src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825 index cd01f87b3..cd01f87b3 100644 --- a/src/mint/afl-tests/id:001096,src:000004,op:flip1,pos:8825 +++ b/src/exchange/afl-tests/id:001096,src:000004,op:flip1,pos:8825 diff --git a/src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov b/src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov index 2c1d2d546..2c1d2d546 100644 --- a/src/mint/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov +++ b/src/exchange/afl-tests/id:001097,src:000004,op:flip1,pos:8840,+cov diff --git a/src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov b/src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov index 05c296667..05c296667 100644 --- a/src/mint/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov +++ b/src/exchange/afl-tests/id:001098,src:000004,op:flip1,pos:8869,+cov diff --git a/src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov b/src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov index f01f684ee..f01f684ee 100644 --- a/src/mint/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov +++ b/src/exchange/afl-tests/id:001099,src:000004,op:flip1,pos:8882,+cov diff --git a/src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov b/src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov index 0e7f71998..0e7f71998 100644 --- a/src/mint/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov +++ b/src/exchange/afl-tests/id:001100,src:000004,op:flip1,pos:8910,+cov diff --git a/src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov b/src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov index 3caaafdad..3caaafdad 100644 --- a/src/mint/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov +++ b/src/exchange/afl-tests/id:001101,src:000004,op:flip1,pos:9001,+cov diff --git a/src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov b/src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov index 8362c9819..8362c9819 100644 --- a/src/mint/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov +++ b/src/exchange/afl-tests/id:001102,src:000004,op:flip1,pos:9584,+cov diff --git a/src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov b/src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov index fdd838ccf..fdd838ccf 100644 --- a/src/mint/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov +++ b/src/exchange/afl-tests/id:001103,src:000004,op:flip1,pos:9658,+cov diff --git a/src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov b/src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov index 7c078ab2e..7c078ab2e 100644 --- a/src/mint/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov +++ b/src/exchange/afl-tests/id:001104,src:000004,op:flip1,pos:9808,+cov diff --git a/src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov b/src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov index 6e5a956d3..6e5a956d3 100644 --- a/src/mint/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov +++ b/src/exchange/afl-tests/id:001105,src:000004,op:flip1,pos:9954,+cov diff --git a/src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov b/src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov index d306d0041..d306d0041 100644 --- a/src/mint/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov +++ b/src/exchange/afl-tests/id:001106,src:000004,op:flip1,pos:10093,+cov diff --git a/src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417 b/src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417 index c0e323631..c0e323631 100644 --- a/src/mint/afl-tests/id:001107,src:000004,op:flip1,pos:10417 +++ b/src/exchange/afl-tests/id:001107,src:000004,op:flip1,pos:10417 diff --git a/src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov b/src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov index 026431f36..026431f36 100644 --- a/src/mint/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov +++ b/src/exchange/afl-tests/id:001108,src:000004,op:flip1,pos:10430,+cov diff --git a/src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639 b/src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639 index 73fd35c1b..73fd35c1b 100644 --- a/src/mint/afl-tests/id:001109,src:000004,op:flip1,pos:10639 +++ b/src/exchange/afl-tests/id:001109,src:000004,op:flip1,pos:10639 diff --git a/src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846 b/src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846 index cf9c6fa7d..cf9c6fa7d 100644 --- a/src/mint/afl-tests/id:001110,src:000004,op:flip1,pos:10846 +++ b/src/exchange/afl-tests/id:001110,src:000004,op:flip1,pos:10846 diff --git a/src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov b/src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov index 720af50ab..720af50ab 100644 --- a/src/mint/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov +++ b/src/exchange/afl-tests/id:001111,src:000004,op:flip1,pos:10957,+cov diff --git a/src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055 b/src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055 index 8d61f7536..8d61f7536 100644 --- a/src/mint/afl-tests/id:001112,src:000004,op:flip1,pos:11055 +++ b/src/exchange/afl-tests/id:001112,src:000004,op:flip1,pos:11055 diff --git a/src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov b/src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov index a967cf97f..a967cf97f 100644 --- a/src/mint/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov +++ b/src/exchange/afl-tests/id:001113,src:000004,op:flip1,pos:11176,+cov diff --git a/src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262 b/src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262 index 96039612c..96039612c 100644 --- a/src/mint/afl-tests/id:001114,src:000004,op:flip1,pos:11262 +++ b/src/exchange/afl-tests/id:001114,src:000004,op:flip1,pos:11262 diff --git a/src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471 b/src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471 index 1ff255bc3..1ff255bc3 100644 --- a/src/mint/afl-tests/id:001115,src:000004,op:flip1,pos:11471 +++ b/src/exchange/afl-tests/id:001115,src:000004,op:flip1,pos:11471 diff --git a/src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887 b/src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887 index 050fb05fb..050fb05fb 100644 --- a/src/mint/afl-tests/id:001116,src:000004,op:flip1,pos:11887 +++ b/src/exchange/afl-tests/id:001116,src:000004,op:flip1,pos:11887 diff --git a/src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov b/src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov index e699099e4..e699099e4 100644 --- a/src/mint/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov +++ b/src/exchange/afl-tests/id:001117,src:000004,op:flip1,pos:11996,+cov diff --git a/src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094 b/src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094 index e0e030e9c..e0e030e9c 100644 --- a/src/mint/afl-tests/id:001118,src:000004,op:flip1,pos:12094 +++ b/src/exchange/afl-tests/id:001118,src:000004,op:flip1,pos:12094 diff --git a/src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302 b/src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302 index 9f75ab625..9f75ab625 100644 --- a/src/mint/afl-tests/id:001119,src:000004,op:flip1,pos:12302 +++ b/src/exchange/afl-tests/id:001119,src:000004,op:flip1,pos:12302 diff --git a/src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511 b/src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511 index ed4428acb..ed4428acb 100644 --- a/src/mint/afl-tests/id:001120,src:000004,op:flip1,pos:12511 +++ b/src/exchange/afl-tests/id:001120,src:000004,op:flip1,pos:12511 diff --git a/src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov b/src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov index 08f6634a0..08f6634a0 100644 --- a/src/mint/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov +++ b/src/exchange/afl-tests/id:001121,src:000004,op:flip1,pos:12567,+cov diff --git a/src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov b/src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov index b312ac3db..b312ac3db 100644 --- a/src/mint/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov +++ b/src/exchange/afl-tests/id:001122,src:000004,op:flip1,pos:12660,+cov diff --git a/src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342 b/src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342 index 792fae008..792fae008 100644 --- a/src/mint/afl-tests/id:001123,src:000004,op:flip1,pos:13342 +++ b/src/exchange/afl-tests/id:001123,src:000004,op:flip1,pos:13342 diff --git a/src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550 b/src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550 index 07f0ec7ad..07f0ec7ad 100644 --- a/src/mint/afl-tests/id:001124,src:000004,op:flip1,pos:13550 +++ b/src/exchange/afl-tests/id:001124,src:000004,op:flip1,pos:13550 diff --git a/src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758 b/src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758 index ba1194e1b..ba1194e1b 100644 --- a/src/mint/afl-tests/id:001125,src:000004,op:flip1,pos:13758 +++ b/src/exchange/afl-tests/id:001125,src:000004,op:flip1,pos:13758 diff --git a/src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968 b/src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968 index 59dba82f5..59dba82f5 100644 --- a/src/mint/afl-tests/id:001126,src:000004,op:flip1,pos:13968 +++ b/src/exchange/afl-tests/id:001126,src:000004,op:flip1,pos:13968 diff --git a/src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov b/src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov index a663f1e95..a663f1e95 100644 --- a/src/mint/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov +++ b/src/exchange/afl-tests/id:001127,src:000004,op:flip1,pos:14134,+cov diff --git a/src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov b/src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov index 6b452af69..6b452af69 100644 --- a/src/mint/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov +++ b/src/exchange/afl-tests/id:001128,src:000004,op:flip1,pos:14599,+cov diff --git a/src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603 b/src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603 index e1b7165f9..e1b7165f9 100644 --- a/src/mint/afl-tests/id:001129,src:000004,op:flip1,pos:14603 +++ b/src/exchange/afl-tests/id:001129,src:000004,op:flip1,pos:14603 diff --git a/src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov b/src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov index e749065db..e749065db 100644 --- a/src/mint/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov +++ b/src/exchange/afl-tests/id:001130,src:000004,op:flip1,pos:15122,+cov diff --git a/src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov b/src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov index 61150d582..61150d582 100644 --- a/src/mint/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov +++ b/src/exchange/afl-tests/id:001131,src:000004,op:flip1,pos:15271,+cov diff --git a/src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov b/src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov index 41dd314c4..41dd314c4 100644 --- a/src/mint/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov +++ b/src/exchange/afl-tests/id:001132,src:000004,op:flip1,pos:15295,+cov diff --git a/src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov b/src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov index 3dc90c6c2..3dc90c6c2 100644 --- a/src/mint/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov +++ b/src/exchange/afl-tests/id:001133,src:000004,op:flip1,pos:16328,+cov diff --git a/src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507 b/src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507 index d2edebbec..d2edebbec 100644 --- a/src/mint/afl-tests/id:001134,src:000004,op:flip1,pos:17507 +++ b/src/exchange/afl-tests/id:001134,src:000004,op:flip1,pos:17507 diff --git a/src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov b/src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov index b54170879..b54170879 100644 --- a/src/mint/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov +++ b/src/exchange/afl-tests/id:001135,src:000004,op:flip1,pos:17983,+cov diff --git a/src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov b/src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov index 1dd885533..1dd885533 100644 --- a/src/mint/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov +++ b/src/exchange/afl-tests/id:001136,src:000004,op:flip1,pos:18109,+cov diff --git a/src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov b/src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov index 75e95e32d..75e95e32d 100644 --- a/src/mint/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov +++ b/src/exchange/afl-tests/id:001137,src:000004,op:flip1,pos:19291,+cov diff --git a/src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov b/src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov index 2890e6c10..2890e6c10 100644 --- a/src/mint/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov +++ b/src/exchange/afl-tests/id:001138,src:000004,op:flip1,pos:20068,+cov diff --git a/src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov b/src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov index 48ad875c6..48ad875c6 100644 --- a/src/mint/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov +++ b/src/exchange/afl-tests/id:001139,src:000004,op:flip1,pos:20075,+cov diff --git a/src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov b/src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov index 38c57fd06..38c57fd06 100644 --- a/src/mint/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov +++ b/src/exchange/afl-tests/id:001140,src:000004,op:flip1,pos:20264,+cov diff --git a/src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov b/src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov index 8fba732a9..8fba732a9 100644 --- a/src/mint/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov +++ b/src/exchange/afl-tests/id:001141,src:000004,op:flip1,pos:20372,+cov diff --git a/src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov b/src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov index 4f04fd011..4f04fd011 100644 --- a/src/mint/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov +++ b/src/exchange/afl-tests/id:001142,src:000004,op:flip1,pos:20845,+cov diff --git a/src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044 b/src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044 index fd82bee8f..fd82bee8f 100644 --- a/src/mint/afl-tests/id:001143,src:000004,op:flip1,pos:21044 +++ b/src/exchange/afl-tests/id:001143,src:000004,op:flip1,pos:21044 diff --git a/src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov b/src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov index 2f38588d1..2f38588d1 100644 --- a/src/mint/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov +++ b/src/exchange/afl-tests/id:001144,src:000004,op:flip1,pos:21072,+cov diff --git a/src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov b/src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov index 188621bac..188621bac 100644 --- a/src/mint/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov +++ b/src/exchange/afl-tests/id:001145,src:000004,op:flip1,pos:22111,+cov diff --git a/src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov b/src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov index 7494f020a..7494f020a 100644 --- a/src/mint/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov +++ b/src/exchange/afl-tests/id:001146,src:000004,op:flip1,pos:22404,+cov diff --git a/src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov b/src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov index 0aa3df33d..0aa3df33d 100644 --- a/src/mint/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov +++ b/src/exchange/afl-tests/id:001147,src:000004,op:flip1,pos:23777,+cov diff --git a/src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov b/src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov index 8592c8246..8592c8246 100644 --- a/src/mint/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov +++ b/src/exchange/afl-tests/id:001148,src:000004,op:flip1,pos:24046,+cov diff --git a/src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov b/src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov index 7c25b2134..7c25b2134 100644 --- a/src/mint/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov +++ b/src/exchange/afl-tests/id:001149,src:000004,op:flip1,pos:27360,+cov diff --git a/src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov b/src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov index e7ca1358b..e7ca1358b 100644 --- a/src/mint/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov +++ b/src/exchange/afl-tests/id:001150,src:000004,op:flip1,pos:27547,+cov diff --git a/src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov b/src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov index e985cc465..e985cc465 100644 --- a/src/mint/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov +++ b/src/exchange/afl-tests/id:001151,src:000004,op:flip1,pos:28206,+cov diff --git a/src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov b/src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov index 33d0a93a6..33d0a93a6 100644 --- a/src/mint/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov +++ b/src/exchange/afl-tests/id:001152,src:000004,op:flip1,pos:29132,+cov diff --git a/src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov b/src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov index 2dbd09187..2dbd09187 100644 --- a/src/mint/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov +++ b/src/exchange/afl-tests/id:001153,src:000004,op:flip1,pos:29181,+cov diff --git a/src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov b/src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov index 87d7c814c..87d7c814c 100644 --- a/src/mint/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov +++ b/src/exchange/afl-tests/id:001154,src:000004,op:flip1,pos:30141,+cov diff --git a/src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov b/src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov index 4aae7452e..4aae7452e 100644 --- a/src/mint/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov +++ b/src/exchange/afl-tests/id:001155,src:000004,op:flip1,pos:30860,+cov diff --git a/src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov b/src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov index 2a7aae7b3..2a7aae7b3 100644 --- a/src/mint/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov +++ b/src/exchange/afl-tests/id:001156,src:000004,op:flip1,pos:31016,+cov diff --git a/src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov b/src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov index 6381e638c..6381e638c 100644 --- a/src/mint/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov +++ b/src/exchange/afl-tests/id:001157,src:000004,op:flip1,pos:31260,+cov diff --git a/src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov b/src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov index e6d0f83ce..e6d0f83ce 100644 --- a/src/mint/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov +++ b/src/exchange/afl-tests/id:001158,src:000004,op:flip1,pos:32301,+cov diff --git a/src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov b/src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov index d74dd910f..d74dd910f 100644 --- a/src/mint/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov +++ b/src/exchange/afl-tests/id:001159,src:000004,op:flip1,pos:32476,+cov diff --git a/src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov b/src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov index c0ec2ba7d..c0ec2ba7d 100644 --- a/src/mint/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov +++ b/src/exchange/afl-tests/id:001160,src:000004,op:flip1,pos:33475,+cov diff --git a/src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108 b/src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108 index 08a344286..08a344286 100644 --- a/src/mint/afl-tests/id:001161,src:000004,op:flip2,pos:108 +++ b/src/exchange/afl-tests/id:001161,src:000004,op:flip2,pos:108 diff --git a/src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov b/src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov index e6ec6a90e..e6ec6a90e 100644 --- a/src/mint/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov +++ b/src/exchange/afl-tests/id:001162,src:000004,op:flip2,pos:272,+cov diff --git a/src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov b/src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov index 14ef8b87f..14ef8b87f 100644 --- a/src/mint/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov +++ b/src/exchange/afl-tests/id:001163,src:000004,op:flip2,pos:501,+cov diff --git a/src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov b/src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov index bd6df83eb..bd6df83eb 100644 --- a/src/mint/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov +++ b/src/exchange/afl-tests/id:001164,src:000004,op:flip2,pos:1593,+cov diff --git a/src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov b/src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov index 22acc5fee..22acc5fee 100644 --- a/src/mint/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov +++ b/src/exchange/afl-tests/id:001165,src:000004,op:flip2,pos:1877,+cov diff --git a/src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov b/src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov index 672547a3d..672547a3d 100644 --- a/src/mint/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov +++ b/src/exchange/afl-tests/id:001166,src:000004,op:flip2,pos:2863,+cov diff --git a/src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov b/src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov index a0fb164be..a0fb164be 100644 --- a/src/mint/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov +++ b/src/exchange/afl-tests/id:001167,src:000004,op:flip2,pos:3189,+cov diff --git a/src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov b/src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov index f6eec0890..f6eec0890 100644 --- a/src/mint/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov +++ b/src/exchange/afl-tests/id:001168,src:000004,op:flip2,pos:5916,+cov diff --git a/src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov b/src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov index b3ab01d8e..b3ab01d8e 100644 --- a/src/mint/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov +++ b/src/exchange/afl-tests/id:001169,src:000004,op:flip2,pos:6474,+cov diff --git a/src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov b/src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov index eaa82fafc..eaa82fafc 100644 --- a/src/mint/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov +++ b/src/exchange/afl-tests/id:001170,src:000004,op:flip2,pos:8695,+cov diff --git a/src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov b/src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov index 36104fb8a..36104fb8a 100644 --- a/src/mint/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov +++ b/src/exchange/afl-tests/id:001171,src:000004,op:flip2,pos:9101,+cov diff --git a/src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov b/src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov index b2ab18004..b2ab18004 100644 --- a/src/mint/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov +++ b/src/exchange/afl-tests/id:001172,src:000004,op:flip2,pos:9350,+cov diff --git a/src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov b/src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov index 70e9b6959..70e9b6959 100644 --- a/src/mint/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov +++ b/src/exchange/afl-tests/id:001173,src:000004,op:flip2,pos:9675,+cov diff --git a/src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov b/src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov index b194779d6..b194779d6 100644 --- a/src/mint/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov +++ b/src/exchange/afl-tests/id:001174,src:000004,op:flip2,pos:9779,+cov diff --git a/src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov b/src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov index 80862b397..80862b397 100644 --- a/src/mint/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov +++ b/src/exchange/afl-tests/id:001175,src:000004,op:flip2,pos:10123,+cov diff --git a/src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov b/src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov index e97fdf9e1..e97fdf9e1 100644 --- a/src/mint/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov +++ b/src/exchange/afl-tests/id:001176,src:000004,op:flip2,pos:10486,+cov diff --git a/src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov b/src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov index dd9e8b6ad..dd9e8b6ad 100644 --- a/src/mint/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov +++ b/src/exchange/afl-tests/id:001177,src:000004,op:flip2,pos:11222,+cov diff --git a/src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov b/src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov index 5cb583de8..5cb583de8 100644 --- a/src/mint/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov +++ b/src/exchange/afl-tests/id:001178,src:000004,op:flip2,pos:11504,+cov diff --git a/src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov b/src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov index 50ce154eb..50ce154eb 100644 --- a/src/mint/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov +++ b/src/exchange/afl-tests/id:001179,src:000004,op:flip2,pos:13892,+cov diff --git a/src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov b/src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov index 782604aea..782604aea 100644 --- a/src/mint/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov +++ b/src/exchange/afl-tests/id:001180,src:000004,op:flip2,pos:14104,+cov diff --git a/src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov b/src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov index 98d26fbcf..98d26fbcf 100644 --- a/src/mint/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov +++ b/src/exchange/afl-tests/id:001181,src:000004,op:flip2,pos:16451,+cov diff --git a/src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov b/src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov index 625521f0a..625521f0a 100644 --- a/src/mint/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov +++ b/src/exchange/afl-tests/id:001182,src:000004,op:flip2,pos:17186,+cov diff --git a/src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov b/src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov index df4bd5be2..df4bd5be2 100644 --- a/src/mint/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov +++ b/src/exchange/afl-tests/id:001183,src:000004,op:flip2,pos:18869,+cov diff --git a/src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov b/src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov index 731c6c4c9..731c6c4c9 100644 --- a/src/mint/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov +++ b/src/exchange/afl-tests/id:001184,src:000004,op:flip2,pos:20039,+cov diff --git a/src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov b/src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov index 0c3c81b24..0c3c81b24 100644 --- a/src/mint/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov +++ b/src/exchange/afl-tests/id:001185,src:000004,op:flip2,pos:20319,+cov diff --git a/src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov b/src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov index 65513a07f..65513a07f 100644 --- a/src/mint/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov +++ b/src/exchange/afl-tests/id:001186,src:000004,op:flip2,pos:20987,+cov diff --git a/src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov b/src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov index d96e4d747..d96e4d747 100644 --- a/src/mint/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov +++ b/src/exchange/afl-tests/id:001187,src:000004,op:flip2,pos:22115,+cov diff --git a/src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov b/src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov index 017d9644a..017d9644a 100644 --- a/src/mint/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov +++ b/src/exchange/afl-tests/id:001188,src:000004,op:flip2,pos:22139,+cov diff --git a/src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov b/src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov index 216475300..216475300 100644 --- a/src/mint/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov +++ b/src/exchange/afl-tests/id:001189,src:000004,op:flip2,pos:22530,+cov diff --git a/src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov b/src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov index 4ecbdcd52..4ecbdcd52 100644 --- a/src/mint/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov +++ b/src/exchange/afl-tests/id:001190,src:000004,op:flip2,pos:22871,+cov diff --git a/src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov b/src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov index ae2ab029c..ae2ab029c 100644 --- a/src/mint/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov +++ b/src/exchange/afl-tests/id:001191,src:000004,op:flip2,pos:22878,+cov diff --git a/src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov b/src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov index 6f5703478..6f5703478 100644 --- a/src/mint/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov +++ b/src/exchange/afl-tests/id:001192,src:000004,op:flip2,pos:23586,+cov diff --git a/src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov b/src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov index ec03c6265..ec03c6265 100644 --- a/src/mint/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov +++ b/src/exchange/afl-tests/id:001193,src:000004,op:flip2,pos:24806,+cov diff --git a/src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov b/src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov index b06de9308..b06de9308 100644 --- a/src/mint/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov +++ b/src/exchange/afl-tests/id:001194,src:000004,op:flip2,pos:25248,+cov diff --git a/src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov b/src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov index b88986ca7..b88986ca7 100644 --- a/src/mint/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov +++ b/src/exchange/afl-tests/id:001195,src:000004,op:flip2,pos:26529,+cov diff --git a/src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov b/src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov index 015f1b603..015f1b603 100644 --- a/src/mint/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov +++ b/src/exchange/afl-tests/id:001196,src:000004,op:flip2,pos:28158,+cov diff --git a/src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov b/src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov index 361c69fd7..361c69fd7 100644 --- a/src/mint/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov +++ b/src/exchange/afl-tests/id:001197,src:000004,op:flip2,pos:29113,+cov diff --git a/src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov b/src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov index a4a563eaf..a4a563eaf 100644 --- a/src/mint/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov +++ b/src/exchange/afl-tests/id:001198,src:000004,op:flip2,pos:29233,+cov diff --git a/src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov b/src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov index a8996d176..a8996d176 100644 --- a/src/mint/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov +++ b/src/exchange/afl-tests/id:001199,src:000004,op:flip2,pos:31755,+cov diff --git a/src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov b/src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov index 513c55c33..513c55c33 100644 --- a/src/mint/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov +++ b/src/exchange/afl-tests/id:001200,src:000004,op:flip2,pos:32441,+cov diff --git a/src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov b/src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov index 9b9de1add..9b9de1add 100644 --- a/src/mint/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov +++ b/src/exchange/afl-tests/id:001201,src:000004,op:flip2,pos:32888,+cov diff --git a/src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov b/src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov index 52d4e76cc..52d4e76cc 100644 --- a/src/mint/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov +++ b/src/exchange/afl-tests/id:001202,src:000004,op:flip2,pos:33869,+cov diff --git a/src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov b/src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov index 26b452c41..26b452c41 100644 --- a/src/mint/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov +++ b/src/exchange/afl-tests/id:001203,src:000004,op:flip4,pos:399,+cov diff --git a/src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov b/src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov index 4cb6df571..4cb6df571 100644 --- a/src/mint/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov +++ b/src/exchange/afl-tests/id:001204,src:000004,op:flip4,pos:1377,+cov diff --git a/src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov b/src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov index bc2e00325..bc2e00325 100644 --- a/src/mint/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov +++ b/src/exchange/afl-tests/id:001205,src:000004,op:flip4,pos:1830,+cov diff --git a/src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov b/src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov index 5f2516cd4..5f2516cd4 100644 --- a/src/mint/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov +++ b/src/exchange/afl-tests/id:001206,src:000004,op:flip4,pos:3239,+cov diff --git a/src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov b/src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov index 3ce4d373e..3ce4d373e 100644 --- a/src/mint/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov +++ b/src/exchange/afl-tests/id:001207,src:000004,op:flip4,pos:3591,+cov diff --git a/src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov b/src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov index 23825d180..23825d180 100644 --- a/src/mint/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov +++ b/src/exchange/afl-tests/id:001208,src:000004,op:flip4,pos:3708,+cov diff --git a/src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov b/src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov index 5d902fd15..5d902fd15 100644 --- a/src/mint/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov +++ b/src/exchange/afl-tests/id:001209,src:000004,op:flip4,pos:4350,+cov diff --git a/src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov b/src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov index 5b9b2bf3a..5b9b2bf3a 100644 --- a/src/mint/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov +++ b/src/exchange/afl-tests/id:001210,src:000004,op:flip4,pos:4487,+cov diff --git a/src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov b/src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov index a00c97a9d..a00c97a9d 100644 --- a/src/mint/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov +++ b/src/exchange/afl-tests/id:001211,src:000004,op:flip4,pos:4584,+cov diff --git a/src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov b/src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov index 7607e8165..7607e8165 100644 --- a/src/mint/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov +++ b/src/exchange/afl-tests/id:001212,src:000004,op:flip4,pos:5470,+cov diff --git a/src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov b/src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov index 73f228a96..73f228a96 100644 --- a/src/mint/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov +++ b/src/exchange/afl-tests/id:001213,src:000004,op:flip4,pos:6559,+cov diff --git a/src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov b/src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov index 94de8dcbe..94de8dcbe 100644 --- a/src/mint/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov +++ b/src/exchange/afl-tests/id:001214,src:000004,op:flip4,pos:6626,+cov diff --git a/src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov b/src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov index c98df919a..c98df919a 100644 --- a/src/mint/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov +++ b/src/exchange/afl-tests/id:001215,src:000004,op:flip4,pos:7110,+cov diff --git a/src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov b/src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov index 8c764fce7..8c764fce7 100644 --- a/src/mint/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov +++ b/src/exchange/afl-tests/id:001216,src:000004,op:flip4,pos:7148,+cov diff --git a/src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov b/src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov index 2d65f69c7..2d65f69c7 100644 --- a/src/mint/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov +++ b/src/exchange/afl-tests/id:001217,src:000004,op:flip4,pos:7168,+cov diff --git a/src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov b/src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov index 03b777caf..03b777caf 100644 --- a/src/mint/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov +++ b/src/exchange/afl-tests/id:001218,src:000004,op:flip4,pos:7715,+cov diff --git a/src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov b/src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov index 889eb7e03..889eb7e03 100644 --- a/src/mint/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov +++ b/src/exchange/afl-tests/id:001219,src:000004,op:flip4,pos:9108,+cov diff --git a/src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov b/src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov index 92e0834e8..92e0834e8 100644 --- a/src/mint/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov +++ b/src/exchange/afl-tests/id:001220,src:000004,op:flip4,pos:9386,+cov diff --git a/src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov b/src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov index 6d40e15c5..6d40e15c5 100644 --- a/src/mint/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov +++ b/src/exchange/afl-tests/id:001221,src:000004,op:flip4,pos:9592,+cov diff --git a/src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov b/src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov index d625ba258..d625ba258 100644 --- a/src/mint/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov +++ b/src/exchange/afl-tests/id:001222,src:000004,op:flip4,pos:9878,+cov diff --git a/src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov b/src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov index ff5c27c4e..ff5c27c4e 100644 --- a/src/mint/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov +++ b/src/exchange/afl-tests/id:001223,src:000004,op:flip4,pos:9972,+cov diff --git a/src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov b/src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov index 045286f69..045286f69 100644 --- a/src/mint/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov +++ b/src/exchange/afl-tests/id:001224,src:000004,op:flip4,pos:10287,+cov diff --git a/src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov b/src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov index c396ea742..c396ea742 100644 --- a/src/mint/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov +++ b/src/exchange/afl-tests/id:001225,src:000004,op:flip4,pos:10737,+cov diff --git a/src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov b/src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov index f67390f3e..f67390f3e 100644 --- a/src/mint/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov +++ b/src/exchange/afl-tests/id:001226,src:000004,op:flip4,pos:12260,+cov diff --git a/src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov b/src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov index eeb4d1dd2..eeb4d1dd2 100644 --- a/src/mint/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov +++ b/src/exchange/afl-tests/id:001227,src:000004,op:flip4,pos:15195,+cov diff --git a/src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov b/src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov index b2ae1fa9b..b2ae1fa9b 100644 --- a/src/mint/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov +++ b/src/exchange/afl-tests/id:001228,src:000004,op:flip4,pos:15571,+cov diff --git a/src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov b/src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov index 7593747d4..7593747d4 100644 --- a/src/mint/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov +++ b/src/exchange/afl-tests/id:001229,src:000004,op:flip4,pos:19500,+cov diff --git a/src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov b/src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov index b55c57fcf..b55c57fcf 100644 --- a/src/mint/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov +++ b/src/exchange/afl-tests/id:001230,src:000004,op:flip4,pos:20444,+cov diff --git a/src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov b/src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov index f6da540e8..f6da540e8 100644 --- a/src/mint/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov +++ b/src/exchange/afl-tests/id:001231,src:000004,op:flip4,pos:22249,+cov diff --git a/src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov b/src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov index 020367553..020367553 100644 --- a/src/mint/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov +++ b/src/exchange/afl-tests/id:001232,src:000004,op:flip4,pos:22380,+cov diff --git a/src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov b/src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov index a0a5cbdc5..a0a5cbdc5 100644 --- a/src/mint/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov +++ b/src/exchange/afl-tests/id:001233,src:000004,op:flip4,pos:25459,+cov diff --git a/src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov b/src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov index 19f230d0c..19f230d0c 100644 --- a/src/mint/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov +++ b/src/exchange/afl-tests/id:001234,src:000004,op:flip4,pos:27094,+cov diff --git a/src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov b/src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov index 8d4aeaa25..8d4aeaa25 100644 --- a/src/mint/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov +++ b/src/exchange/afl-tests/id:001235,src:000004,op:flip4,pos:28097,+cov diff --git a/src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov b/src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov index a8531a72d..a8531a72d 100644 --- a/src/mint/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov +++ b/src/exchange/afl-tests/id:001236,src:000004,op:flip4,pos:28763,+cov diff --git a/src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov b/src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov index 12ffe2886..12ffe2886 100644 --- a/src/mint/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov +++ b/src/exchange/afl-tests/id:001237,src:000004,op:flip4,pos:28897,+cov diff --git a/src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov b/src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov index 46c9cb5d0..46c9cb5d0 100644 --- a/src/mint/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov +++ b/src/exchange/afl-tests/id:001238,src:000004,op:flip4,pos:29158,+cov diff --git a/src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov b/src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov index 23f6d573b..23f6d573b 100644 --- a/src/mint/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov +++ b/src/exchange/afl-tests/id:001239,src:000004,op:flip4,pos:29314,+cov diff --git a/src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov b/src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov index d15412a4d..d15412a4d 100644 --- a/src/mint/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov +++ b/src/exchange/afl-tests/id:001240,src:000004,op:flip4,pos:29379,+cov diff --git a/src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov b/src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov index a6c94b3c9..a6c94b3c9 100644 --- a/src/mint/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov +++ b/src/exchange/afl-tests/id:001241,src:000004,op:flip4,pos:30828,+cov diff --git a/src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov b/src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov index c883d866c..c883d866c 100644 --- a/src/mint/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov +++ b/src/exchange/afl-tests/id:001242,src:000004,op:flip4,pos:31450,+cov diff --git a/src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov b/src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov index 76b9110ec..76b9110ec 100644 --- a/src/mint/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov +++ b/src/exchange/afl-tests/id:001243,src:000004,op:flip4,pos:32113,+cov diff --git a/src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov b/src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov index ddad3915e..ddad3915e 100644 --- a/src/mint/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov +++ b/src/exchange/afl-tests/id:001244,src:000004,op:flip4,pos:32563,+cov diff --git a/src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov b/src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov index ee4227257..ee4227257 100644 --- a/src/mint/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov +++ b/src/exchange/afl-tests/id:001245,src:000004,op:flip4,pos:32844,+cov diff --git a/src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov b/src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov index cb37e5bbe..cb37e5bbe 100644 --- a/src/mint/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov +++ b/src/exchange/afl-tests/id:001246,src:000004,op:flip4,pos:33202,+cov diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c new file mode 100644 index 000000000..3ffce1d3f --- /dev/null +++ b/src/exchange/taler-exchange-aggregator.c @@ -0,0 +1,914 @@ +/* + This file is part of TALER + Copyright (C) 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-aggregator.c + * @brief Process that aggregates outgoing transactions and executes them + * @author Christian Grothoff + * + * TODO: + * - simplify global_ret: make it a global! + * - handle shutdown more nicely (call 'cancel' method on wire transfers) + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <pthread.h> +#include "taler_exchangedb_lib.h" +#include "taler_exchangedb_plugin.h" +#include "taler_wire_lib.h" + +/** + * Which currency is used by this exchange? + */ +static char *exchange_currency_string; + +/** + * Which wireformat should be supported by this aggregator? + */ +static char *exchange_wireformat; + +/** + * Base directory of the exchange (global) + */ +static char *exchange_directory; + +/** + * The exchange's configuration (global) + */ +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Our DB plugin. + */ +static struct TALER_EXCHANGEDB_Plugin *db_plugin; + +/** + * Our wire plugin. + */ +static struct TALER_WIRE_Plugin *wire_plugin; + +/** + * Task for the main #run() function. + */ +static struct GNUNET_SCHEDULER_Task *task; + +/** + * Limit on the number of transactions we aggregate at once. Note + * that the limit must be big enough to ensure that when transactions + * of the smallest possible unit are aggregated, they do surpass the + * "tiny" threshold beyond which we never trigger a wire transaction! + * + * TODO: make configurable (via config file or command line option) + */ +static unsigned int aggregation_limit = 10000; + + +/** + * Load configuration parameters for the exchange + * server into the corresponding global variables. + * + * @param exchange_directory the exchange's directory + * @return #GNUNET_OK on success + */ +static int +exchange_serve_process_config (const char *exchange_directory) +{ + char *type; + + cfg = TALER_config_load (exchange_directory); + if (NULL == cfg) + { + fprintf (stderr, + "Failed to load exchange configuration\n"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "currency", + &exchange_currency_string)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "currency"); + return GNUNET_SYSERR; + } + if (strlen (exchange_currency_string) >= TALER_CURRENCY_LEN) + { + fprintf (stderr, + "Currency `%s' longer than the allowed limit of %u characters.", + exchange_currency_string, + (unsigned int) TALER_CURRENCY_LEN); + return GNUNET_SYSERR; + } + if (NULL != exchange_wireformat) + GNUNET_CONFIGURATION_set_value_string (cfg, + "exchange", + "wireformat", + exchange_wireformat); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "wireformat", + &type)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "wireformat"); + return GNUNET_SYSERR; + } + + if (NULL == + (db_plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + fprintf (stderr, + "Failed to initialize DB subsystem\n"); + GNUNET_free (type); + return GNUNET_SYSERR; + } + + if (NULL == + (wire_plugin = TALER_WIRE_plugin_load (cfg, + type))) + { + fprintf (stderr, + "Failed to load wire plugin for `%s'\n", + type); + GNUNET_free (type); + return GNUNET_SYSERR; + } + GNUNET_free (type); + + return GNUNET_OK; +} + + +/** + * Information about one aggregation process to + * be executed. + */ +struct AggregationUnit +{ + /** + * Public key of the merchant. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Total amount to be transferred. + */ + struct TALER_Amount total_amount; + + /** + * Hash of @e wire. + */ + struct GNUNET_HashCode h_wire; + + /** + * Wire transfer identifier we use. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Row ID of the transaction that started it all. + */ + unsigned long long row_id; + + /** + * The current time. + */ + struct GNUNET_TIME_Absolute execution_time; + + /** + * Wire details of the merchant. + */ + json_t *wire; + + /** + * Database session for all of our transactions. + */ + struct TALER_EXCHANGEDB_Session *session; + + /** + * Wire preparation handle. + */ + struct TALER_WIRE_PrepareHandle *ph; + + /** + * Array of #aggregation_limit row_ids from the + * aggregation. + */ + unsigned long long *additional_rows; + + /** + * Pointer to global return value. Closure for #run(). + */ + int *global_ret; + + /** + * Offset specifying how many #additional_rows are in use. + */ + unsigned int rows_offset; + + /** + * Set to #GNUNET_YES if we have to abort due to failure. + */ + int failed; + +}; + + +/** + * Function called with details about deposits that have been made, + * with the goal of executing the corresponding wire transaction. + * + * @param cls closure with the `struct AggregationUnit` + * @param row_id identifies database entry + * @param merchant_pub public key of the merchant + * @param coin_pub public key of the coin + * @param amount_with_fee amount that was deposited including fee + * @param deposit_fee amount the exchange gets to keep as transaction fees + * @param transaction_id unique transaction ID chosen by the merchant + * @param h_contract hash of the contract between merchant and customer + * @param wire_deadline by which the merchant adviced that he would like the + * wire transfer to be executed + * @param wire wire details for the merchant + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +static int +deposit_cb (void *cls, + unsigned long long row_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + uint64_t transaction_id, + const struct GNUNET_HashCode *h_contract, + struct GNUNET_TIME_Absolute wire_deadline, + const json_t *wire) +{ + struct AggregationUnit *au = cls; + + au->merchant_pub = *merchant_pub; + if (GNUNET_OK != + TALER_amount_subtract (&au->total_amount, + amount_with_fee, + deposit_fee)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fatally malformed record at %llu\n", + row_id); + return GNUNET_SYSERR; + } + au->row_id = row_id; + au->wire = (json_t *) wire; + au->execution_time = GNUNET_TIME_absolute_get (); + TALER_hash_json (au->wire, + &au->h_wire); + json_incref (au->wire); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &au->wtid, + sizeof (au->wtid)); + if (GNUNET_OK != + db_plugin->insert_aggregation_tracking (db_plugin->cls, + au->session, + &au->wtid, + merchant_pub, + &au->h_wire, + h_contract, + transaction_id, + au->execution_time, + coin_pub, + amount_with_fee, + deposit_fee)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + db_plugin->mark_deposit_done (db_plugin->cls, + au->session, + row_id)) + { + GNUNET_break (0); + au->failed = GNUNET_YES; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + + +/** + * Function called with details about another deposit we + * can aggregate into an existing aggregation unit. + * + * @param cls closure with the `struct AggregationUnit` + * @param row_id identifies database entry + * @param merchant_pub public key of the merchant + * @param coin_pub public key of the coin + * @param amount_with_fee amount that was deposited including fee + * @param deposit_fee amount the exchange gets to keep as transaction fees + * @param transaction_id unique transaction ID chosen by the merchant + * @param h_contract hash of the contract between merchant and customer + * @param wire_deadline by which the merchant adviced that he would like the + * wire transfer to be executed + * @param wire wire details for the merchant + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +static int +aggregate_cb (void *cls, + unsigned long long row_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + uint64_t transaction_id, + const struct GNUNET_HashCode *h_contract, + struct GNUNET_TIME_Absolute wire_deadline, + const json_t *wire) +{ + struct AggregationUnit *au = cls; + struct TALER_Amount delta; + + GNUNET_break (0 == + memcmp (&au->merchant_pub, + merchant_pub, + sizeof (struct TALER_MerchantPublicKeyP))); + /* compute contribution of this coin after fees */ + if (GNUNET_OK != + TALER_amount_subtract (&delta, + amount_with_fee, + deposit_fee)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fatally malformed record at %llu\n", + row_id); + return GNUNET_SYSERR; + } + /* add to total */ + if (GNUNET_OK != + TALER_amount_add (&au->total_amount, + &au->total_amount, + &delta)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Overflow or currency incompatibility during aggregation at %llu\n", + row_id); + /* Skip this one, but keep going! */ + return GNUNET_OK; + } + if (au->rows_offset >= aggregation_limit) + { + /* Bug: we asked for at most #aggregation_limit results! */ + GNUNET_break (0); + /* Skip this one, but keep going. */ + return GNUNET_OK; + } + if (NULL == au->additional_rows) + au->additional_rows = GNUNET_new_array (aggregation_limit, + unsigned long long); + /* "append" to our list of rows */ + au->additional_rows[au->rows_offset++] = row_id; + /* insert into aggregation tracking table */ + if (GNUNET_OK != + db_plugin->insert_aggregation_tracking (db_plugin->cls, + au->session, + &au->wtid, + merchant_pub, + &au->h_wire, + h_contract, + transaction_id, + au->execution_time, + coin_pub, + amount_with_fee, + deposit_fee)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + db_plugin->mark_deposit_done (db_plugin->cls, + au->session, + row_id)) + { + GNUNET_break (0); + au->failed = GNUNET_YES; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Function to be called with the prepared transfer data. + * + * @param cls closure with the `struct AggregationUnit` + * @param buf transaction data to persist, NULL on error + * @param buf_size number of bytes in @a buf, 0 on error + */ +static void +prepare_cb (void *cls, + const char *buf, + size_t buf_size); + + +/** + * Main work function that queries the DB and aggregates transactions + * into larger wire transfers. + * + * @param cls pointer to an `int` which we will return from main() + * @param tc scheduler context + */ +static void +run_aggregation (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *global_ret = cls; + struct TALER_EXCHANGEDB_Session *session; + struct AggregationUnit *au; + unsigned int i; + int ret; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + if (NULL == (session = db_plugin->get_session (db_plugin->cls, + GNUNET_NO))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to obtain database session!\n"); + *global_ret = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + db_plugin->start (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to start database transaction!\n"); + *global_ret = GNUNET_SYSERR; + return; + } + au = GNUNET_new (struct AggregationUnit); + au->session = session; + ret = db_plugin->get_ready_deposit (db_plugin->cls, + session, + &deposit_cb, + au); + if (GNUNET_OK != ret) + { + GNUNET_free (au); + db_plugin->rollback (db_plugin->cls, + session); + if (0 != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to execute deposit iteration!\n"); + *global_ret = GNUNET_SYSERR; + return; + } + /* nothing to do, sleep for a minute and try again */ + task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &run_aggregation, + global_ret); + return; + } + /* Now try to find other deposits to aggregate */ + ret = db_plugin->iterate_matching_deposits (db_plugin->cls, + session, + &au->h_wire, + &au->merchant_pub, + &aggregate_cb, + au, + aggregation_limit); + if ( (GNUNET_SYSERR == ret) || + (GNUNET_YES == au->failed) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to execute deposit iteration!\n"); + GNUNET_free_non_null (au->additional_rows); + GNUNET_free (au); + db_plugin->rollback (db_plugin->cls, + session); + *global_ret = GNUNET_SYSERR; + return; + } + /* Round to the unit supported by the wire transfer method */ + GNUNET_assert (GNUNET_SYSERR != + wire_plugin->amount_round (wire_plugin->cls, + &au->total_amount)); + /* Check if after rounding down, we still have an amount to transfer */ + if ( (0 == au->total_amount.value) && + (0 == au->total_amount.fraction) ) + { + /* Rollback ongoing transaction, as we will not use the respective + WTID and thus need to remove the tracking data */ + db_plugin->rollback (db_plugin->cls, + session); + /* Start another transaction to mark all* of the selected deposits + *as minor! */ + if (GNUNET_OK != + db_plugin->start (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to start database transaction!\n"); + *global_ret = GNUNET_SYSERR; + GNUNET_free_non_null (au->additional_rows); + GNUNET_free (au); + return; + } + /* Mark transactions by row_id as minor */ + ret = GNUNET_OK; + if (GNUNET_OK != + db_plugin->mark_deposit_tiny (db_plugin->cls, + session, + au->row_id)) + ret = GNUNET_SYSERR; + else + for (i=0;i<au->rows_offset;i++) + if (GNUNET_OK != + db_plugin->mark_deposit_tiny (db_plugin->cls, + session, + au->additional_rows[i])) + ret = GNUNET_SYSERR; + /* commit */ + if (GNUNET_OK != + db_plugin->commit (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to commit database transaction!\n"); + } + GNUNET_free_non_null (au->additional_rows); + GNUNET_free (au); + /* start again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + au->global_ret = global_ret; + au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls, + au->wire, + &au->total_amount, + &au->wtid, + &prepare_cb, + au); + /* FIXME: currently we have no clean-up plan on + shutdown to call prepare_wire_transfer_cancel! + Maybe make 'au' global? */ + if (NULL == au->ph) + { + GNUNET_break (0); /* why? how to best recover? */ + db_plugin->rollback (db_plugin->cls, + session); + GNUNET_free_non_null (au->additional_rows); + GNUNET_free (au); + /* start again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + /* otherwise we continue with #prepare_cb(), see below */ +} + + +/** + * Execute the wire transfers that we have committed to + * do. + * + * @param cls pointer to an `int` which we will return from main() + * @param tc scheduler context + */ +static void +run_transfers (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function to be called with the prepared transfer data. + * + * @param cls closure with the `struct AggregationUnit` + * @param buf transaction data to persist, NULL on error + * @param buf_size number of bytes in @a buf, 0 on error + */ +static void +prepare_cb (void *cls, + const char *buf, + size_t buf_size) +{ + struct AggregationUnit *au = cls; + int *global_ret = au->global_ret; + struct TALER_EXCHANGEDB_Session *session = au->session; + + GNUNET_free_non_null (au->additional_rows); + GNUNET_free (au); + if (NULL == buf) + { + GNUNET_break (0); /* why? how to best recover? */ + db_plugin->rollback (db_plugin->cls, + session); + /* start again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + + /* Commit our intention to execute the wire transfer! */ + if (GNUNET_OK != + db_plugin->wire_prepare_data_insert (db_plugin->cls, + session, + exchange_wireformat, + buf, + buf_size)) + { + GNUNET_break (0); /* why? how to best recover? */ + db_plugin->rollback (db_plugin->cls, + session); + /* start again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + + /* Now we can finally commit the overall transaction, as we are + again consistent if all of this passes. */ + if (GNUNET_OK != + db_plugin->commit (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Failed to commit database transaction!\n"); + /* try again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + + /* run alternative task: actually do wire transfer! */ + task = GNUNET_SCHEDULER_add_now (&run_transfers, + &global_ret); +} + + +/** + * Data we keep to #run_transfers(). + */ +struct WirePrepareData +{ + + /** + * Database session for all of our transactions. + */ + struct TALER_EXCHANGEDB_Session *session; + + /** + * Wire execution handle. + */ + struct TALER_WIRE_ExecuteHandle *eh; + + /** + * Pointer to global return value. Closure for #run(). + */ + int *global_ret; + + + /** + * Row ID of the transfer. + */ + unsigned long long row_id; + +}; + + +/** + * Function called with the result from the execute step. + * + * @param cls closure with the `struct WirePrepareData` + * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure + * @param emsg NULL on success, otherwise an error message + */ +static void +wire_confirm_cb (void *cls, + int success, + const char *emsg) +{ + struct WirePrepareData *wpd = cls; + int *global_ret = wpd->global_ret; + struct TALER_EXCHANGEDB_Session *session = wpd->session; + + wpd->eh = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire transaction failed: %s\n", + emsg); + db_plugin->rollback (db_plugin->cls, + session); + *global_ret = GNUNET_SYSERR; + GNUNET_free (wpd); + return; + } + if (GNUNET_OK != + db_plugin->wire_prepare_data_mark_finished (db_plugin->cls, + session, + wpd->row_id)) + { + GNUNET_break (0); /* why!? */ + db_plugin->rollback (db_plugin->cls, + session); + *global_ret = GNUNET_SYSERR; + GNUNET_free (wpd); + return; + } + GNUNET_free (wpd); + if (GNUNET_OK != + db_plugin->commit (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Failed to commit database transaction!\n"); + /* try again */ + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + return; + } + /* continue with #run_transfers(), just to guard + against the unlikely case that there are more. */ + task = GNUNET_SCHEDULER_add_now (&run_transfers, + &global_ret); + +} + + +/** + * Callback with data about a prepared transaction. + * + * @param cls closure with the `struct WirePrepareData` + * @param rowid row identifier used to mark prepared transaction as done + * @param buf transaction data that was persisted, NULL on error + * @param buf_size number of bytes in @a buf, 0 on error + */ +static void +wire_prepare_cb (void *cls, + unsigned long long rowid, + const char *buf, + size_t buf_size) +{ + struct WirePrepareData *wpd = cls; + int *global_ret = wpd->global_ret; + + wpd->row_id = rowid; + wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls, + buf, + buf_size, + &wire_confirm_cb, + wpd); + /* FIXME: currently we have no clean-up plan on + shutdown to call execute_wire_transfer_cancel! + Maybe make 'wpd' global? */ + if (NULL == wpd->eh) + { + GNUNET_break (0); /* why? how to best recover? */ + db_plugin->rollback (db_plugin->cls, + wpd->session); + *global_ret = GNUNET_SYSERR; + GNUNET_free (wpd); + return; + } +} + + +/** + * Execute the wire transfers that we have committed to + * do. + * + * @param cls pointer to an `int` which we will return from main() + * @param tc scheduler context + */ +static void +run_transfers (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + int *global_ret = cls; + int ret; + struct WirePrepareData *wpd; + struct TALER_EXCHANGEDB_Session *session; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + if (NULL == (session = db_plugin->get_session (db_plugin->cls, + GNUNET_NO))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to obtain database session!\n"); + *global_ret = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + db_plugin->start (db_plugin->cls, + session)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to start database transaction!\n"); + *global_ret = GNUNET_SYSERR; + return; + } + wpd = GNUNET_new (struct WirePrepareData); + wpd->session = session; + wpd->global_ret = global_ret; + ret = db_plugin->wire_prepare_data_get (db_plugin->cls, + session, + exchange_wireformat, + &wire_prepare_cb, + wpd); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); /* why? how to best recover? */ + db_plugin->rollback (db_plugin->cls, + session); + *global_ret = GNUNET_SYSERR; + GNUNET_free (wpd); + return; + } + if (GNUNET_NO == ret) + { + /* no more prepared wire transfers, go back to aggregation! */ + db_plugin->rollback (db_plugin->cls, + session); + task = GNUNET_SCHEDULER_add_now (&run_aggregation, + global_ret); + GNUNET_free (wpd); + return; + } + /* otherwise, continues in #wire_prepare_cb() */ +} + + +/** + * The main function of the taler-exchange-httpd server ("the exchange"). + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'d', "exchange-dir", "DIR", + "exchange directory with configuration and keys for operating the exchange", 1, + &GNUNET_GETOPT_set_filename, &exchange_directory}, + {'f', "format", "WIREFORMAT", + "wireformat to use, overrides WIREFORMAT option in [exchange] section", 1, + &GNUNET_GETOPT_set_filename, &exchange_wireformat}, + TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"), + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + int ret = GNUNET_OK; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-aggregator", + "INFO", + NULL)); + if (0 >= + GNUNET_GETOPT_run ("taler-exchange-aggregator", + options, + argc, argv)) + return 1; + if (NULL == exchange_directory) + { + fprintf (stderr, + "Exchange directory not specified\n"); + return 1; + } + if (GNUNET_OK != + exchange_serve_process_config (exchange_directory)) + { + return 1; + } + + GNUNET_SCHEDULER_run (&run_transfers, &ret); + + TALER_EXCHANGEDB_plugin_unload (db_plugin); + TALER_WIRE_plugin_unload (wire_plugin); + return (GNUNET_SYSERR == ret) ? 1 : 0; +} + +/* end of taler-exchange-aggregator.c */ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c new file mode 100644 index 000000000..c16e26409 --- /dev/null +++ b/src/exchange/taler-exchange-httpd.c @@ -0,0 +1,749 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd.c + * @brief Serve the HTTP interface of the exchange + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_mhd.h" +#include "taler-exchange-httpd_admin.h" +#include "taler-exchange-httpd_deposit.h" +#include "taler-exchange-httpd_reserve.h" +#include "taler-exchange-httpd_wire.h" +#include "taler-exchange-httpd_refresh.h" +#include "taler-exchange-httpd_tracking.h" +#include "taler-exchange-httpd_keystate.h" +#if HAVE_DEVELOPER +#include "taler-exchange-httpd_test.h" +#endif +#include "taler_exchangedb_plugin.h" +#include "taler-exchange-httpd_validation.h" + +/** + * Which currency is used by this exchange? + */ +char *TMH_exchange_currency_string; + +/** + * Should we return "Connection: close" in each response? + */ +int TMH_exchange_connection_close; + +/** + * Base directory of the exchange (global) + */ +char *TMH_exchange_directory; + +/** + * The exchange's configuration (global) + */ +struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Master public key (according to the + * configuration in the exchange directory). + */ +struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key; + +/** + * Our DB plugin. + */ +struct TALER_EXCHANGEDB_Plugin *TMH_plugin; + +/** + * Are we running in test mode? + */ +int TMH_test_mode; + +/** + * Default timeout in seconds for HTTP requests. + */ +static unsigned int connection_timeout = 30; + +/** + * The HTTP Daemon. + */ +static struct MHD_Daemon *mydaemon; + +/** + * Port to run the daemon on. + */ +static uint16_t serve_port; + + +/** + * Function called whenever MHD is done with a request. If the + * request was a POST, we may have stored a `struct Buffer *` in the + * @a con_cls that might still need to be cleaned up. Call the + * respective function to free the memory. + * + * @param cls client-defined closure + * @param connection connection handle + * @param con_cls value as set by the last call to + * the #MHD_AccessHandlerCallback + * @param toe reason for request termination + * @see #MHD_OPTION_NOTIFY_COMPLETED + * @ingroup request + */ +static void +handle_mhd_completion_callback (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + if (NULL == *con_cls) + return; + TMH_PARSE_post_cleanup_callback (*con_cls); + *con_cls = NULL; +} + + +/** + * Handle a request coming from libmicrohttpd. + * + * @param cls closure for MHD daemon (unused) + * @param connection the connection + * @param url the requested url + * @param method the method (POST, GET, ...) + * @param version HTTP version (ignored) + * @param upload_data request data + * @param upload_data_size size of @a upload_data in bytes + * @param con_cls closure for request (a `struct Buffer *`) + * @return MHD result code + */ +static int +handle_mhd_request (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + static struct TMH_RequestHandler handlers[] = + { + /* Landing page, tell humans to go away. */ + { "/", MHD_HTTP_METHOD_GET, "text/plain", + "Hello, I'm the Taler exchange. This HTTP server is not for humans.\n", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_OK }, + /* /robots.txt: disallow everything */ + { "/robots.txt", MHD_HTTP_METHOD_GET, "text/plain", + "User-agent: *\nDisallow: /\n", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_OK }, + /* AGPL licensing page, redirect to source. As per the AGPL-license, + every deployment is required to offer the user a download of the + source. We make this easy by including a redirect to the source + here. */ + { "/agpl", MHD_HTTP_METHOD_GET, "text/plain", + NULL, 0, + &TMH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND }, + + /* Return key material and fundamental properties for this exchange */ + { "/keys", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_KS_handler_keys, MHD_HTTP_OK }, + { "/keys", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + /* Requests for wiring information */ + { "/wire", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_WIRE_handler_wire, MHD_HTTP_OK }, + { "/wire", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/wire/test", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_WIRE_handler_wire_test, MHD_HTTP_FOUND }, + { "/wire/test", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/wire/sepa", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_WIRE_handler_wire_sepa, MHD_HTTP_OK }, + { "/wire/sepa", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + /* Withdrawing coins / interaction with reserves */ + { "/reserve/status", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_RESERVE_handler_reserve_status, MHD_HTTP_OK }, + { "/reserve/status", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/reserve/withdraw", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_RESERVE_handler_reserve_withdraw, MHD_HTTP_OK }, + { "/reserve/withdraw", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + /* Depositing coins */ + { "/deposit", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_DEPOSIT_handler_deposit, MHD_HTTP_OK }, + { "/deposit", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + /* Dealing with change */ + { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_REFRESH_handler_refresh_melt, MHD_HTTP_OK }, + { "/refresh/melt", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK }, + { "/refresh/reveal", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK }, + { "/refresh/reveal", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_REFRESH_handler_refresh_link, MHD_HTTP_OK }, + { "/refresh/link", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + /* FIXME: maybe conditionally compile these? */ + { "/admin/add/incoming", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_ADMIN_handler_admin_add_incoming, MHD_HTTP_OK }, + { "/admin/add/incoming", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/wire/deposits", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_TRACKING_handler_wire_deposits, MHD_HTTP_OK }, + { "/wire/deposits", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + { "/deposit/wtid", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TRACKING_handler_deposit_wtid, MHD_HTTP_OK }, + { "/deposit/wtid", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + +#if HAVE_DEVELOPER + /* Client crypto-interoperability test functions */ + { "/test", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test, MHD_HTTP_OK }, + { "/test", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/base32", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_base32, MHD_HTTP_OK }, + { "/test/base32", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/encrypt", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_encrypt, MHD_HTTP_OK }, + { "/test/encrypt", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/hkdf", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_hkdf, MHD_HTTP_OK }, + { "/test/hkdf", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/ecdhe", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_ecdhe, MHD_HTTP_OK }, + { "/test/ecdhe", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/eddsa", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_eddsa, MHD_HTTP_OK }, + { "/test/eddsa", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/rsa/get", MHD_HTTP_METHOD_GET, "application/json", + NULL, 0, + &TMH_TEST_handler_test_rsa_get, MHD_HTTP_OK }, + { "/test/rsa/get", NULL, "text/plain", + "Only GET is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/rsa/sign", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_rsa_sign, MHD_HTTP_OK }, + { "/test/rsa/sign", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, + + { "/test/transfer", MHD_HTTP_METHOD_POST, "application/json", + NULL, 0, + &TMH_TEST_handler_test_transfer, MHD_HTTP_OK }, + { "/test/transfer", NULL, "text/plain", + "Only POST is allowed", 0, + &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, +#endif + + { NULL, NULL, NULL, NULL, 0, 0 } + }; + static struct TMH_RequestHandler h404 = + { + "", NULL, "text/html", + "<html><title>404: not found</title></html>", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND + }; + struct TMH_RequestHandler *rh; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling request for URL '%s'\n", + url); + for (i=0;NULL != handlers[i].url;i++) + { + rh = &handlers[i]; + if ( (0 == strcasecmp (url, + rh->url)) && + ( (NULL == rh->method) || + (0 == strcasecmp (method, + rh->method)) ) ) + return rh->handler (rh, + connection, + con_cls, + upload_data, + upload_data_size); + } + return TMH_MHD_handler_static_response (&h404, + connection, + con_cls, + upload_data, + upload_data_size); +} + + +/** + * Load configuration parameters for the exchange + * server into the corresponding global variables. + * + * @param exchange_directory the exchange's directory + * @return #GNUNET_OK on success + */ +static int +exchange_serve_process_config (const char *exchange_directory) +{ + unsigned long long port; + char *TMH_master_public_key_str; + + cfg = TALER_config_load (exchange_directory); + if (NULL == cfg) + { + fprintf (stderr, + "Failed to load exchange configuration\n"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "currency", + &TMH_exchange_currency_string)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "currency"); + return GNUNET_SYSERR; + } + if (strlen (TMH_exchange_currency_string) >= TALER_CURRENCY_LEN) + { + fprintf (stderr, + "Currency `%s' longer than the allowed limit of %u characters.", + TMH_exchange_currency_string, + (unsigned int) TALER_CURRENCY_LEN); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TMH_VALIDATION_init (cfg)) + return GNUNET_SYSERR; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "master_public_key", + &TMH_master_public_key_str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "master_public_key"); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (TMH_master_public_key_str, + strlen (TMH_master_public_key_str), + &TMH_master_public_key)) + { + fprintf (stderr, + "Invalid master public key given in exchange configuration."); + GNUNET_free (TMH_master_public_key_str); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + GNUNET_free (TMH_master_public_key_str); + + if (NULL == + (TMH_plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + fprintf (stderr, + "Failed to initialize DB subsystem\n"); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (cfg, + "exchange", + "TESTRUN")) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Running in TEST mode! Database contents will not persist!\n"); + TMH_test_mode = GNUNET_YES; + TMH_plugin->create_tables (TMH_plugin->cls, + GNUNET_YES); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "exchange", + "port", + &port)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "port", + "port number required"); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + + if ( (0 == port) || + (port > UINT16_MAX) ) + { + fprintf (stderr, + "Invalid configuration (value out of range): %llu is not a valid port\n", + port); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + serve_port = (uint16_t) port; + + return GNUNET_OK; +} + + +/* Developer logic for supporting the `-f' option. */ +#if HAVE_DEVELOPER + +/** + * Option `-f' (specifies an input file to give to the HTTP server). + */ +static char *input_filename; + + +/** + * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename + * as the input for the request. If launching the client worked, + * run the #TMH_KS_loop() event loop as usual. + * + * @return #GNUNET_OK + */ +static int +run_fake_client () +{ + pid_t cld; + char ports[6]; + int fd; + int ret; + int status; + + fd = open (input_filename, O_RDONLY); + if (-1 == fd) + { + fprintf (stderr, + "Failed to open `%s': %s\n", + input_filename, + strerror (errno)); + return GNUNET_SYSERR; + } + /* Fake HTTP client request with #input_filename as input. + We do this using the nc tool. */ + GNUNET_snprintf (ports, + sizeof (ports), + "%u", + serve_port); + if (0 == (cld = fork())) + { + GNUNET_break (0 == close (0)); + GNUNET_break (0 == dup2 (fd, 0)); + GNUNET_break (0 == close (fd)); + if ( (0 != execlp ("nc", + "nc", + "localhost", + ports, + "-w", "30", + NULL)) && + (0 != execlp ("ncat", + "ncat", + "localhost", + ports, + "-i", "30", + NULL)) ) + { + fprintf (stderr, + "Failed to run both `nc' and `ncat': %s\n", + strerror (errno)); + } + _exit (1); + } + /* parent process */ + GNUNET_break (0 == close (fd)); + ret = TMH_KS_loop (); + if (cld != waitpid (cld, &status, 0)) + fprintf (stderr, + "Waiting for `nc' child failed: %s\n", + strerror (errno)); + return ret; +} + + +/** + * Signature of the callback used by MHD to notify the application + * about completed connections. If we are running in test-mode with + * an #input_filename, this function is used to terminate the HTTPD + * after the first request has been processed. + * + * @param cls client-defined closure, NULL + * @param connection connection handle (ignored) + * @param socket_context socket-specific pointer (ignored) + * @param toe reason for connection notification + */ +static void +connection_done (void *cls, + struct MHD_Connection *connection, + void **socket_context, + enum MHD_ConnectionNotificationCode toe) +{ + /* We only act if the connection is closed. */ + if (MHD_CONNECTION_NOTIFY_CLOSED != toe) + return; + /* This callback is also present if the option wasn't, so + make sure the option was actually set. */ + if (NULL == input_filename) + return; + /* We signal ourselves to terminate. */ + if (0 != kill (getpid(), + SIGTERM)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "kill"); +} + +/* end of HAVE_DEVELOPER */ +#endif + + +/** + * Function called for logging by MHD. + * + * @param cls closure, NULL + * @param fm format string (`printf()`-style) + * @param ap arguments to @a fm + */ +static void +handle_mhd_logs (void *cls, + const char *fm, + va_list ap) +{ + char buf[2048]; + + vsnprintf (buf, + sizeof (buf), + fm, + ap); + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "libmicrohttpd", + "%s", + buf); +} + + +/** + * The main function of the taler-exchange-httpd server ("the exchange"). + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'C', "connection-close", NULL, + "force HTTP connections to be closed after each request", 0, + &GNUNET_GETOPT_set_one, &TMH_exchange_connection_close}, + {'d', "exchange-dir", "DIR", + "exchange directory with configuration and keys for operating the exchange", 1, + &GNUNET_GETOPT_set_filename, &TMH_exchange_directory}, + {'t', "timeout", "SECONDS", + "after how long do connections timeout by default (in seconds)", 1, + &GNUNET_GETOPT_set_uint, &connection_timeout}, +#if HAVE_DEVELOPER + {'f', "file-input", "FILENAME", + "run in test-mode using FILENAME as the HTTP request to process", 1, + &GNUNET_GETOPT_set_filename, &input_filename}, +#endif + TALER_GETOPT_OPTION_HELP ("HTTP server providing a RESTful API to access a Taler exchange"), + GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), + GNUNET_GETOPT_OPTION_END + }; + int ret; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-httpd", + "INFO", + NULL)); + if (0 >= + GNUNET_GETOPT_run ("taler-exchange-httpd", + options, + argc, argv)) + return 1; + if (NULL == TMH_exchange_directory) + { + fprintf (stderr, + "Exchange directory not specified\n"); + return 1; + } + + if (GNUNET_OK != + exchange_serve_process_config (TMH_exchange_directory)) + return 1; + + mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + serve_port, + NULL, NULL, + &handle_mhd_request, NULL, + MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL, + MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout, +#if HAVE_DEVELOPER + MHD_OPTION_NOTIFY_CONNECTION, &connection_done, NULL, +#endif + MHD_OPTION_END); + + if (NULL == mydaemon) + { + fprintf (stderr, + "Failed to start HTTP server.\n"); + return 1; + } +#if HAVE_DEVELOPER + if (NULL != input_filename) + { + /* run only the testfile input, then terminate */ + ret = run_fake_client (); + } + else + { + /* normal behavior */ + ret = TMH_KS_loop (); + } +#else + /* normal behavior */ + ret = TMH_KS_loop (); +#endif + + switch (ret) + { + case GNUNET_OK: + case GNUNET_SYSERR: + MHD_stop_daemon (mydaemon); + break; + case GNUNET_NO: + { + MHD_socket sock = MHD_quiesce_daemon (mydaemon); + + /* FIXME #3474: fork another MHD, passing on the listen socket! */ + while (0 != MHD_get_daemon_info (mydaemon, + MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections) + sleep (1); + MHD_stop_daemon (mydaemon); + + close (sock); /* FIXME: done like this because #3474 is open */ + } + break; + default: + GNUNET_break (0); + MHD_stop_daemon (mydaemon); + break; + } + + if (GNUNET_YES == TMH_test_mode) + { + struct TALER_EXCHANGEDB_Session *session; + + session = TMH_plugin->get_session (TMH_plugin->cls, + GNUNET_YES); + if (NULL == session) + GNUNET_break (0); + else + TMH_plugin->drop_temporary (TMH_plugin->cls, + session); + } + TALER_EXCHANGEDB_plugin_unload (TMH_plugin); + TMH_VALIDATION_done (); + return (GNUNET_SYSERR == ret) ? 1 : 0; +} + +/* end of taler-exchange-httpd.c */ diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h new file mode 100644 index 000000000..5f17eac5b --- /dev/null +++ b/src/exchange/taler-exchange-httpd.h @@ -0,0 +1,128 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd.h + * @brief Global declarations for the exchange + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + * + * FIXME: Consider which of these need to really be globals... + */ +#ifndef TALER_EXCHANGE_HTTPD_H +#define TALER_EXCHANGE_HTTPD_H + +#include <microhttpd.h> + + +/** + * Which currency is used by this exchange? + */ +extern char *TMH_exchange_currency_string; + +/** + * Should we return "Connection: close" in each response? + */ +extern int TMH_exchange_connection_close; + +/** + * The exchange's configuration. + */ +extern struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Are we running in test mode? + */ +extern int TMH_test_mode; + +/** + * Main directory with exchange data. + */ +extern char *TMH_exchange_directory; + +/** + * Master public key (according to the + * configuration in the exchange directory). + */ +extern struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key; + +/** + * Private key of the exchange we use to sign messages. + */ +extern struct GNUNET_CRYPTO_EddsaPrivateKey TMH_exchange_private_signing_key; + +/** + * Our DB plugin. + */ +extern struct TALER_EXCHANGEDB_Plugin *TMH_plugin; + + +/** + * @brief Struct describing an URL and the handler for it. + */ +struct TMH_RequestHandler +{ + + /** + * URL the handler is for. + */ + const char *url; + + /** + * Method the handler is for, NULL for "all". + */ + const char *method; + + /** + * Mime type to use in reply (hint, can be NULL). + */ + const char *mime_type; + + /** + * Raw data for the @e handler + */ + const void *data; + + /** + * Number of bytes in @e data, 0 for 0-terminated. + */ + size_t data_size; + + /** + * Function to call to handle the request. + * + * @param rh this struct + * @param mime_type the @e mime_type for the reply (hint, can be NULL) + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ + int (*handler)(struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + /** + * Default response code. + */ + int response_code; +}; + + +#endif diff --git a/src/exchange/taler-exchange-httpd_admin.c b/src/exchange/taler-exchange-httpd_admin.c new file mode 100644 index 000000000..575df7bb0 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_admin.c @@ -0,0 +1,164 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_admin.c + * @brief Handle /admin/ requests + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include "taler-exchange-httpd_admin.h" +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_validation.h" + + +/** + * Check permissions (we only allow access to /admin/ from loopback). + * + * @param connection connection to perform access check for + * @return #GNUNET_OK if permitted, + * #GNUNET_NO if denied and error was queued, + * #GNUNET_SYSERR if denied and we failed to report + */ +static int +check_permissions (struct MHD_Connection *connection) +{ + const union MHD_ConnectionInfo *ci; + const struct sockaddr *addr; + int res; + + ci = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_CLIENT_ADDRESS); + if (NULL == ci) + { + GNUNET_break (0); + res = TMH_RESPONSE_reply_internal_error (connection, + "Failed to verify client address"); + return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; + } + addr = ci->client_addr; + switch (addr->sa_family) + { + case AF_INET: + { + const struct sockaddr_in *sin = (const struct sockaddr_in *) addr; + + if (INADDR_LOOPBACK != ntohl (sin->sin_addr.s_addr)) + { + res = TMH_RESPONSE_reply_permission_denied (connection, + "/admin/ only allowed via loopback"); + return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; + } + break; + } + case AF_INET6: + { + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr; + + if (! IN6_IS_ADDR_LOOPBACK (&sin6->sin6_addr)) + { + res = TMH_RESPONSE_reply_permission_denied (connection, + "/admin/ only allowed via loopback"); + return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; + } + break; + } + default: + GNUNET_break (0); + res = TMH_RESPONSE_reply_internal_error (connection, + "Unsupported AF"); + return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; + } + return GNUNET_OK; +} + + + +/** + * Handle a "/admin/add/incoming" request. Parses the + * given "reserve_pub", "amount", "transaction" and "h_wire" + * details and adds the respective transaction to the database. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_Amount amount; + struct GNUNET_TIME_Absolute at; + json_t *wire; + json_t *root; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub), + TMH_PARSE_member_amount ("amount", &amount), + TMH_PARSE_member_time_abs ("execution_date", &at), + TMH_PARSE_member_object ("wire", &wire), + TMH_PARSE_MEMBER_END + }; + int res; + + res = check_permissions (connection); + if (GNUNET_OK != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == root) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + root, + spec); + json_decref (root); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + json_decref (root); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + if (GNUNET_YES != + TMH_json_validate_wireformat (wire)) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_unknown (connection, + "wire"); + } + res = TMH_DB_execute_admin_add_incoming (connection, + &reserve_pub, + &amount, + at, + wire); + TMH_PARSE_release_data (spec); + return res; +} + +/* end of taler-exchange-httpd_admin.c */ diff --git a/src/exchange/taler-exchange-httpd_admin.h b/src/exchange/taler-exchange-httpd_admin.h new file mode 100644 index 000000000..d720d61d3 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_admin.h @@ -0,0 +1,46 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_admin.h + * @brief Handle /admin/ requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_ADMIN_H +#define TALER_EXCHANGE_HTTPD_ADMIN_H + +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + +/** + * Handle a "/admin/add/incoming" request. Parses the + * given "reserve_pub", "amount", "transaction" and "h_wire" + * details and adds the respective transaction to the database. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + +#endif diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c new file mode 100644 index 000000000..9d04efa9b --- /dev/null +++ b/src/exchange/taler-exchange-httpd_db.c @@ -0,0 +1,1900 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_db.c + * @brief High-level (transactional-layer) database operations for the exchange. + * @author Christian Grothoff + */ +#include "platform.h" +#include <pthread.h> +#include <jansson.h> +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_keystate.h" + +/** + * How often should we retry a transaction before giving up + * (for transactions resulting in serialization/dead locks only). + */ +#define MAX_TRANSACTION_COMMIT_RETRIES 3 + +/** + * Code to begin a transaction, must be inline as we define a block + * that ends with #COMMIT_TRANSACTION() within which we perform a number + * of retries. Note that this code may call "return" internally, so + * it must be called within a function where any cleanup will be done + * by the caller. Furthermore, the function's return value must + * match that of a #TMH_RESPONSE_reply_internal_db_error() status code. + * + * @param session session handle + * @param connection connection handle + */ +#define START_TRANSACTION(session,connection) \ +{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\ + unsigned int transaction_retries = 0; \ + int transaction_commit_result; \ +transaction_start_label: /* we will use goto for retries */ \ + if (GNUNET_OK != \ + TMH_plugin->start (TMH_plugin->cls, \ + session)) \ + { \ + GNUNET_break (0); \ + return TMH_RESPONSE_reply_internal_db_error (connection); \ + } + +/** + * Code to conclude a transaction, dual to #START_TRANSACTION(). Note + * that this code may call "return" internally, so it must be called + * within a function where any cleanup will be done by the caller. + * Furthermore, the function's return value must match that of a + * #TMH_RESPONSE_reply_internal_db_error() status code. + * + * @param session session handle + * @param connection connection handle + */ +#define COMMIT_TRANSACTION(session,connection) \ + transaction_commit_result = \ + TMH_plugin->commit (TMH_plugin->cls, \ + session); \ + if (GNUNET_SYSERR == transaction_commit_result) \ + { \ + TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ + return TMH_RESPONSE_reply_commit_error (connection); \ + } \ + if (GNUNET_NO == transaction_commit_result) \ + { \ + TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ + if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \ + goto transaction_start_label; \ + TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \ + transaction_retries, \ + __FUNCTION__); \ + return TMH_RESPONSE_reply_commit_error (connection); \ + } \ +} /* end of scope opened by BEGIN_TRANSACTION */ + + +/** + * Calculate the total value of all transactions performed. + * Stores @a off plus the cost of all transactions in @a tl + * in @a ret. + * + * @param tl transaction list to process + * @param off offset to use as the starting value + * @param ret where the resulting total is to be stored + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static int +calculate_transaction_list_totals (struct TALER_EXCHANGEDB_TransactionList *tl, + const struct TALER_Amount *off, + struct TALER_Amount *ret) +{ + struct TALER_Amount spent = *off; + struct TALER_EXCHANGEDB_TransactionList *pos; + + for (pos = tl; NULL != pos; pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_TT_DEPOSIT: + if (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &pos->details.deposit->amount_with_fee)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + break; + case TALER_EXCHANGEDB_TT_REFRESH_MELT: + if (GNUNET_OK != + TALER_amount_add (&spent, + &spent, + &pos->details.melt->amount_with_fee)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + break; + } + } + *ret = spent; + return GNUNET_OK; +} + + +/** + * Execute a deposit. The validity of the coin and signature + * have already been checked. The database must now check that + * the coin is not (double or over) spent, and execute the + * transaction (record details, generate success or failure response). + * + * @param connection the MHD connection to handle + * @param deposit information about the deposit + * @return MHD result code + */ +int +TMH_DB_execute_deposit (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_Deposit *deposit) +{ + struct TALER_EXCHANGEDB_Session *session; + struct TALER_EXCHANGEDB_TransactionList *tl; + struct TALER_Amount spent; + struct TALER_Amount value; + struct TALER_Amount amount_without_fee; + struct TMH_KS_StateHandle *mks; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + int ret; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_YES == + TMH_plugin->have_deposit (TMH_plugin->cls, + session, + deposit)) + { + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&amount_without_fee, + &deposit->amount_with_fee, + &deposit->deposit_fee)); + return TMH_RESPONSE_reply_deposit_success (connection, + &deposit->coin.coin_pub, + &deposit->h_wire, + &deposit->h_contract, + deposit->transaction_id, + deposit->timestamp, + deposit->refund_deadline, + &deposit->merchant_pub, + &amount_without_fee); + } + mks = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (mks, + &deposit->coin.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dki) + { + TMH_KS_release (mks); + return TMH_RESPONSE_reply_arg_invalid (connection, + "denom_pub"); + } + TALER_amount_ntoh (&value, + &dki->issue.properties.value); + TMH_KS_release (mks); + + START_TRANSACTION (session, connection); + + /* fee for THIS transaction */ + spent = deposit->amount_with_fee; + /* add cost of all previous transactions */ + tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, + session, + &deposit->coin.coin_pub); + if (GNUNET_OK != + calculate_transaction_list_totals (tl, + &spent, + &spent)) + { + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + /* Check that cost of all transactions is smaller than + the value of the coin. */ + if (0 < TALER_amount_cmp (&spent, + &value)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + ret = TMH_RESPONSE_reply_deposit_insufficient_funds (connection, + tl); + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + return ret; + } + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + + if (GNUNET_OK != + TMH_plugin->insert_deposit (TMH_plugin->cls, + session, + deposit)) + { + TALER_LOG_WARNING ("Failed to store /deposit information in database\n"); + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + COMMIT_TRANSACTION(session, connection); + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&amount_without_fee, + &deposit->amount_with_fee, + &deposit->deposit_fee)); + return TMH_RESPONSE_reply_deposit_success (connection, + &deposit->coin.coin_pub, + &deposit->h_wire, + &deposit->h_contract, + deposit->transaction_id, + deposit->timestamp, + deposit->refund_deadline, + &deposit->merchant_pub, + &amount_without_fee); +} + + +/** + * Execute a /reserve/status. Given the public key of a reserve, + * return the associated transaction history. + * + * @param connection the MHD connection to handle + * @param reserve_pub public key of the reserve to check + * @return MHD result code + */ +int +TMH_DB_execute_reserve_status (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + struct TALER_EXCHANGEDB_Session *session; + struct TALER_EXCHANGEDB_ReserveHistory *rh; + int res; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, + session, + reserve_pub); + if (NULL == rh) + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s, s:s}", + "error", "Reserve not found", + "parameter", "withdraw_pub"); + res = TMH_RESPONSE_reply_reserve_status_success (connection, + rh); + TMH_plugin->free_reserve_history (TMH_plugin->cls, + rh); + return res; +} + + +/** + * Try to execute /reserve/withdraw transaction. + * + * @param connection request we are handling + * @param session database session we are using + * @param key_state key state to lookup denomination pubs + * @param reserve reserve to withdraw from + * @param denomination_pub public key of the denomination requested + * @param dki denomination to withdraw + * @param blinded_msg blinded message to be signed + * @param blinded_msg_len number of bytes in @a blinded_msg + * @param h_blind hash of @a blinded_msg + * @param signature signature over the withdraw request, to be stored in DB + * @param denom_sig[out] where to write the resulting signature + * (used to release memory in case of transaction failure + * @return MHD result code + */ +static int +execute_reserve_withdraw_transaction (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + struct TMH_KS_StateHandle *key_state, + const struct TALER_ReservePublicKeyP *reserve, + const struct TALER_DenominationPublicKey *denomination_pub, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, + const char *blinded_msg, + size_t blinded_msg_len, + const struct GNUNET_HashCode *h_blind, + const struct TALER_ReserveSignatureP *signature, + struct TALER_DenominationSignature *denom_sig) +{ + struct TALER_EXCHANGEDB_ReserveHistory *rh; + const struct TALER_EXCHANGEDB_ReserveHistory *pos; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *tdki; + struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; + struct TALER_Amount amount_required; + struct TALER_Amount deposit_total; + struct TALER_Amount withdraw_total; + struct TALER_Amount balance; + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + int res; + + /* Check if balance is sufficient */ + START_TRANSACTION (session, connection); + rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, + session, + reserve); + if (NULL == rh) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_arg_unknown (connection, + "reserve_pub"); + } + + /* calculate amount required including fees */ + TALER_amount_ntoh (&value, + &dki->issue.properties.value); + TALER_amount_ntoh (&fee_withdraw, + &dki->issue.properties.fee_withdraw); + + if (GNUNET_OK != + TALER_amount_add (&amount_required, + &value, + &fee_withdraw)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + /* calculate balance of the reserve */ + res = 0; + for (pos = rh; NULL != pos; pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + if (0 == (res & 1)) + deposit_total = pos->details.bank->amount; + else + if (GNUNET_OK != + TALER_amount_add (&deposit_total, + &deposit_total, + &pos->details.bank->amount)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + res |= 1; + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + tdki = TMH_KS_denomination_key_lookup (key_state, + &pos->details.withdraw->denom_pub, + TMH_KS_DKU_WITHDRAW); + if (NULL == tdki) + { + GNUNET_break (0); + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + TALER_amount_ntoh (&value, + &tdki->issue.properties.value); + if (0 == (res & 2)) + withdraw_total = value; + else + if (GNUNET_OK != + TALER_amount_add (&withdraw_total, + &withdraw_total, + &value)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + res |= 2; + break; + } + } + if (0 == (res & 1)) + { + /* did not encounter any deposit operations, how can we have a reserve? */ + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (0 == (res & 2)) + { + /* did not encounter any withdraw operations, set to zero */ + TALER_amount_get_zero (deposit_total.currency, + &withdraw_total); + } + /* All reserve balances should be non-negative */ + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_subtract (&balance, + &deposit_total, + &withdraw_total)); + if (0 < TALER_amount_cmp (&amount_required, + &balance)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + res = TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection, + rh); + TMH_plugin->free_reserve_history (TMH_plugin->cls, + rh); + return res; + } + TMH_plugin->free_reserve_history (TMH_plugin->cls, + rh); + + /* Balance is good, sign the coin! */ + denom_sig->rsa_signature + = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, + blinded_msg, + blinded_msg_len); + if (NULL == denom_sig->rsa_signature) + { + GNUNET_break (0); + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_error (connection, + "Internal error"); + } + collectable.sig = *denom_sig; + collectable.denom_pub = *denomination_pub; + collectable.amount_with_fee = amount_required; + collectable.withdraw_fee = fee_withdraw; + collectable.reserve_pub = *reserve; + collectable.h_coin_envelope = *h_blind; + collectable.reserve_sig = *signature; + if (GNUNET_OK != + TMH_plugin->insert_withdraw_info (TMH_plugin->cls, + session, + &collectable)) + { + GNUNET_break (0); + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + COMMIT_TRANSACTION (session, connection); + + return TMH_RESPONSE_reply_reserve_withdraw_success (connection, + &collectable); +} + + + +/** + * Execute a "/reserve/withdraw". Given a reserve and a properly signed + * request to withdraw a coin, check the balance of the reserve and + * if it is sufficient, store the request and return the signed + * blinded envelope. + * + * @param connection the MHD connection to handle + * @param reserve public key of the reserve + * @param denomination_pub public key of the denomination requested + * @param blinded_msg blinded message to be signed + * @param blinded_msg_len number of bytes in @a blinded_msg + * @param signature signature over the withdraw request, to be stored in DB + * @return MHD result code + */ +int +TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve, + const struct TALER_DenominationPublicKey *denomination_pub, + const char *blinded_msg, + size_t blinded_msg_len, + const struct TALER_ReserveSignatureP *signature) +{ + struct TALER_EXCHANGEDB_Session *session; + struct TMH_KS_StateHandle *key_state; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; + struct TALER_DenominationSignature denom_sig; + struct GNUNET_HashCode h_blind; + int res; + + GNUNET_CRYPTO_hash (blinded_msg, + blinded_msg_len, + &h_blind); + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, + session, + &h_blind, + &collectable); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + /* Don't sign again if we have already signed the coin */ + if (GNUNET_YES == res) + { + res = TMH_RESPONSE_reply_reserve_withdraw_success (connection, + &collectable); + GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); + return res; + } + GNUNET_assert (GNUNET_NO == res); + + key_state = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (key_state, + denomination_pub, + TMH_KS_DKU_WITHDRAW); + if (NULL == dki) + { + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Denomination not found"); + } + denom_sig.rsa_signature = NULL; + res = execute_reserve_withdraw_transaction (connection, + session, + key_state, + reserve, + denomination_pub, + dki, + blinded_msg, + blinded_msg_len, + &h_blind, + signature, + &denom_sig); + if (NULL != denom_sig.rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature); + TMH_KS_release (key_state); + return res; +} + + +/** + * Parse coin melt requests from a JSON object and write them to + * the database. + * + * @param connection the connection to send errors to + * @param session the database connection + * @param key_state the exchange's key state + * @param session_hash hash identifying the refresh session + * @param coin_details details about the coin being melted + * @param oldcoin_index what is the number assigned to this coin + * @return #GNUNET_OK on success, + * #GNUNET_NO if an error message was generated, + * #GNUNET_SYSERR on internal errors (no response generated) + */ +static int +refresh_accept_melts (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + const struct TMH_KS_StateHandle *key_state, + const struct GNUNET_HashCode *session_hash, + const struct TMH_DB_MeltDetails *coin_details, + uint16_t oldcoin_index) +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk; + struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki; + struct TALER_EXCHANGEDB_TransactionList *tl; + struct TALER_Amount coin_value; + struct TALER_Amount coin_residual; + struct TALER_Amount spent; + struct TALER_EXCHANGEDB_RefreshMelt melt; + int res; + + dk = TMH_KS_denomination_key_lookup (key_state, + &coin_details->coin_info.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dk) + return (MHD_YES == + TMH_RESPONSE_reply_arg_unknown (connection, + "denom_pub")) + ? GNUNET_NO : GNUNET_SYSERR; + dki = &dk->issue; + TALER_amount_ntoh (&coin_value, + &dki->properties.value); + /* fee for THIS transaction; the melt amount includes the fee! */ + spent = coin_details->melt_amount_with_fee; + /* add historic transaction costs of this coin */ + tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, + session, + &coin_details->coin_info.coin_pub); + if (GNUNET_OK != + calculate_transaction_list_totals (tl, + &spent, + &spent)) + { + GNUNET_break (0); + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + return (MHD_YES == + TMH_RESPONSE_reply_internal_db_error (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + /* Refuse to refresh when the coin's value is insufficient + for the cost of all transactions. */ + if (TALER_amount_cmp (&coin_value, + &spent) < 0) + { + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&coin_residual, + &spent, + &coin_details->melt_amount_with_fee)); + res = (MHD_YES == + TMH_RESPONSE_reply_refresh_melt_insufficient_funds (connection, + &coin_details->coin_info.coin_pub, + coin_value, + tl, + coin_details->melt_amount_with_fee, + coin_residual)) + ? GNUNET_NO : GNUNET_SYSERR; + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + return res; + } + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); + + melt.coin = coin_details->coin_info; + melt.coin_sig = coin_details->melt_sig; + melt.session_hash = *session_hash; + melt.amount_with_fee = coin_details->melt_amount_with_fee; + melt.melt_fee = coin_details->melt_fee; + if (GNUNET_OK != + TMH_plugin->insert_refresh_melt (TMH_plugin->cls, + session, + oldcoin_index, + &melt)) + { + GNUNET_break (0); + return (MHD_YES == + TMH_RESPONSE_reply_internal_db_error (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Execute a "/refresh/melt". We have been given a list of valid + * coins and a request to melt them into the given + * @a refresh_session_pub. Check that the coins all have the + * required value left and if so, store that they have been + * melted and confirm the melting operation to the client. + * + * @param connection the MHD connection to handle + * @param session_hash hash code of the session the coins are melted into + * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array + * @param denom_pubs public keys of the coins we want to withdraw in the end + * @param coin_count number of entries in @a coin_melt_details, size of y-dimension of @a commit_link array + * @param coin_melt_details signatures and (residual) value of the respective coin should be melted + * @param commit_coin 2d array of coin commitments (what the exchange is to sign + * once the "/refres/reveal" of cut and choose is done), + * x-dimension must be #TALER_CNC_KAPPA + * @param commit_link 2d array of coin link commitments (what the exchange is + * to return via "/refresh/link" to enable linkage in the + * future) + * x-dimension must be #TALER_CNC_KAPPA + * @return MHD result code + */ +int +TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + unsigned int num_new_denoms, + const struct TALER_DenominationPublicKey *denom_pubs, + unsigned int coin_count, + const struct TMH_DB_MeltDetails *coin_melt_details, + struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin, + struct TALER_RefreshCommitLinkP *const* commit_link) +{ + struct TMH_KS_StateHandle *key_state; + struct TALER_EXCHANGEDB_RefreshSession refresh_session; + struct TALER_EXCHANGEDB_Session *session; + int res; + unsigned int i; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + START_TRANSACTION (session, connection); + res = TMH_plugin->get_refresh_session (TMH_plugin->cls, + session, + session_hash, + &refresh_session); + if (GNUNET_YES == res) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + res = TMH_RESPONSE_reply_refresh_melt_success (connection, + session_hash, + refresh_session.noreveal_index); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + if (GNUNET_SYSERR == res) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + /* store 'global' session data */ + refresh_session.num_oldcoins = coin_count; + refresh_session.num_newcoins = num_new_denoms; + refresh_session.noreveal_index + = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, + TALER_CNC_KAPPA); + if (GNUNET_OK != + (res = TMH_plugin->create_refresh_session (TMH_plugin->cls, + session, + session_hash, + &refresh_session))) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + /* Melt old coins and check that they had enough residual value */ + key_state = TMH_KS_acquire (); + for (i=0;i<coin_count;i++) + { + if (GNUNET_OK != + (res = refresh_accept_melts (connection, + session, + key_state, + session_hash, + &coin_melt_details[i], + i))) + { + TMH_KS_release (key_state); + TMH_plugin->rollback (TMH_plugin->cls, + session); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + } + TMH_KS_release (key_state); + + /* store requested new denominations */ + if (GNUNET_OK != + TMH_plugin->insert_refresh_order (TMH_plugin->cls, + session, + session_hash, + num_new_denoms, + denom_pubs)) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + if (GNUNET_OK != + TMH_plugin->insert_refresh_commit_coins (TMH_plugin->cls, + session, + session_hash, + i, + num_new_denoms, + commit_coin[i])) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + } + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + if (GNUNET_OK != + TMH_plugin->insert_refresh_commit_links (TMH_plugin->cls, + session, + session_hash, + i, + coin_count, + commit_link[i])) + { + TMH_plugin->rollback (TMH_plugin->cls, + session); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + } + + COMMIT_TRANSACTION (session, connection); + return TMH_RESPONSE_reply_refresh_melt_success (connection, + session_hash, + refresh_session.noreveal_index); +} + + +/** + * Send an error response with the details of the original melt + * commitment and the location of the mismatch. + * + * @param connection the MHD connection to handle + * @param session database connection to use + * @param session_hash hash of session to query + * @param off commitment offset to check + * @param index index of the mismatch + * @param object_name name of the object with the problem + * @return #GNUNET_NO if we generated the error message + * #GNUNET_SYSERR if we could not even generate an error message + */ +static int +send_melt_commitment_error (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + unsigned int off, + unsigned int index, + const char *object_name) +{ + struct TALER_EXCHANGEDB_MeltCommitment *mc; + int ret; + + mc = TMH_plugin->get_melt_commitment (TMH_plugin->cls, + session, + session_hash); + if (NULL == mc) + { + GNUNET_break (0); + return (MHD_YES == + TMH_RESPONSE_reply_internal_error (connection, + "Melt commitment assembly")) + ? GNUNET_NO : GNUNET_SYSERR; + } + ret = (MHD_YES == + TMH_RESPONSE_reply_refresh_reveal_missmatch (connection, + mc, + off, + index, + object_name)) + ? GNUNET_NO : GNUNET_SYSERR; + TMH_plugin->free_melt_commitment (TMH_plugin->cls, + mc); + return ret; +} + + +/** + * Check if the given @a transfer_privs correspond to an honest + * commitment for the given session. + * Checks that the transfer private keys match their commitments. + * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match. + * + * @param connection the MHD connection to handle + * @param session database connection to use + * @param session_hash hash of session to query + * @param off commitment offset to check + * @param num_oldcoins size of the @a transfer_privs and @a melts arrays + * @param transfer_privs private transfer keys + * @param melts array of melted coins + * @param num_newcoins number of newcoins being generated + * @param denom_pubs array of @a num_newcoins keys for the new coins + * @return #GNUNET_OK if the committment was honest, + * #GNUNET_NO if there was a problem and we generated an error message + * #GNUNET_SYSERR if we could not even generate an error message + */ +static int +check_commitment (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + unsigned int off, + unsigned int num_oldcoins, + const struct TALER_TransferPrivateKeyP *transfer_privs, + const struct TALER_EXCHANGEDB_RefreshMelt *melts, + unsigned int num_newcoins, + const struct TALER_DenominationPublicKey *denom_pubs) +{ + unsigned int j; + struct TALER_LinkSecretP last_shared_secret; + int secret_initialized = GNUNET_NO; + struct TALER_RefreshCommitLinkP *commit_links; + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins; + + commit_links = GNUNET_malloc (num_oldcoins * + sizeof (struct TALER_RefreshCommitLinkP)); + if (GNUNET_OK != + TMH_plugin->get_refresh_commit_links (TMH_plugin->cls, + session, + session_hash, + off, + num_oldcoins, + commit_links)) + { + GNUNET_break (0); + GNUNET_free (commit_links); + return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + + for (j = 0; j < num_oldcoins; j++) + { + struct TALER_LinkSecretP shared_secret; + struct TALER_TransferPublicKeyP transfer_pub_check; + + GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[j].ecdhe_priv, + &transfer_pub_check.ecdhe_pub); + if (0 != + memcmp (&transfer_pub_check, + &commit_links[j].transfer_pub, + sizeof (struct TALER_TransferPublicKeyP))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "transfer keys do not match\n"); + GNUNET_free (commit_links); + return send_melt_commitment_error (connection, + session, + session_hash, + off, + j, + "transfer key"); + } + + if (GNUNET_OK != + TALER_link_decrypt_secret (&commit_links[j].shared_secret_enc, + &transfer_privs[j], + &melts[j].coin.coin_pub, + &shared_secret)) + { + GNUNET_free (commit_links); + return (MHD_YES == + TMH_RESPONSE_reply_internal_error (connection, + "Transfer secret decryption error")) + ? GNUNET_NO : GNUNET_SYSERR; + } + if (GNUNET_NO == secret_initialized) + { + secret_initialized = GNUNET_YES; + last_shared_secret = shared_secret; + } + else if (0 != memcmp (&shared_secret, + &last_shared_secret, + sizeof (struct GNUNET_HashCode))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "shared secrets do not match\n"); + GNUNET_free (commit_links); + return send_melt_commitment_error (connection, + session, + session_hash, + off, + j, + "transfer secret"); + } + } + GNUNET_break (GNUNET_YES == secret_initialized); + GNUNET_free (commit_links); + + /* Check that the commitments for all new coins were correct */ + commit_coins = GNUNET_malloc (num_newcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin)); + + if (GNUNET_OK != + TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, + session, + session_hash, + off, + num_newcoins, + commit_coins)) + { + GNUNET_break (0); + GNUNET_free (commit_coins); + return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + + for (j = 0; j < num_newcoins; j++) + { + struct TALER_RefreshLinkDecrypted *link_data; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode h_msg; + char *buf; + size_t buf_len; + + link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link, + &last_shared_secret); + if (NULL == link_data) + { + GNUNET_break (0); + GNUNET_free (commit_coins); + return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, + "Decryption error")) + ? GNUNET_NO : GNUNET_SYSERR; + } + + GNUNET_CRYPTO_eddsa_key_get_public (&link_data->coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_CRYPTO_hash (&coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP), + &h_msg); + if (0 == (buf_len = + GNUNET_CRYPTO_rsa_blind (&h_msg, + link_data->blinding_key.rsa_blinding_key, + denom_pubs[j].rsa_public_key, + &buf))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "blind failed\n"); + GNUNET_free (commit_coins); + return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, + "Blinding error")) + ? GNUNET_NO : GNUNET_SYSERR; + } + + if ( (buf_len != commit_coins[j].coin_ev_size) || + (0 != memcmp (buf, + commit_coins[j].coin_ev, + buf_len)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "blind envelope does not match for k=%u, old=%d\n", + off, + (int) j); + GNUNET_free (commit_coins); + return send_melt_commitment_error (connection, + session, + session_hash, + off, + j, + "envelope"); + } + GNUNET_free (buf); + } + GNUNET_free (commit_coins); + + return GNUNET_OK; +} + + +/** + * Exchange a coin as part of a refresh operation. Obtains the + * envelope from the database and performs the signing operation. + * + * @param connection the MHD connection to handle + * @param session database connection to use + * @param session_hash hash of session to query + * @param key_state key state to lookup denomination pubs + * @param denom_pub denomination key for the coin to create + * @param commit_coin the coin that was committed + * @param coin_off number of the coin + * @return NULL on error, otherwise signature over the coin + */ +static struct TALER_DenominationSignature +refresh_exchange_coin (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + struct TMH_KS_StateHandle *key_state, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin, + unsigned int coin_off) +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TALER_DenominationSignature ev_sig; + + dki = TMH_KS_denomination_key_lookup (key_state, + denom_pub, + TMH_KS_DKU_WITHDRAW); + if (NULL == dki) + { + GNUNET_break (0); + ev_sig.rsa_signature = NULL; + return ev_sig; + } + ev_sig.rsa_signature + = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, + commit_coin->coin_ev, + commit_coin->coin_ev_size); + if (NULL == ev_sig.rsa_signature) + { + GNUNET_break (0); + return ev_sig; + } + if (GNUNET_OK != + TMH_plugin->insert_refresh_out (TMH_plugin->cls, + session, + session_hash, + coin_off, + &ev_sig)) + { + GNUNET_break (0); + GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature); + ev_sig.rsa_signature = NULL; + } + return ev_sig; +} + + +/** + * The client request was well-formed, now execute the DB transaction + * of a "/refresh/reveal" operation. We use the @a ev_sigs and + * @a commit_coins to clean up resources after this function returns + * as we might experience retries of the database transaction. + * + * @param connection the MHD connection to handle + * @param session database session + * @param session_hash hash identifying the refresh session + * @param refresh_session information about the refresh operation we are doing + * @param melts array of "num_oldcoins" with information about melted coins + * @param denom_pubs array of "num_newcoins" denomination keys for the new coins + * @param[out] ev_sigs where to store generated signatures for the new coins, + * array of length "num_newcoins", memory released by the + * caller + * @param[out] commit_coins array of length "num_newcoins" to be used for + * information about the new coins from the commitment. + * @return MHD result code + */ +static int +execute_refresh_reveal_transaction (struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + const struct TALER_EXCHANGEDB_RefreshSession *refresh_session, + const struct TALER_EXCHANGEDB_RefreshMelt *melts, + const struct TALER_DenominationPublicKey *denom_pubs, + struct TALER_DenominationSignature *ev_sigs, + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins) +{ + unsigned int j; + struct TMH_KS_StateHandle *key_state; + + START_TRANSACTION (session, connection); + if (GNUNET_OK != + TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, + session, + session_hash, + refresh_session->noreveal_index, + refresh_session->num_newcoins, + commit_coins)) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + key_state = TMH_KS_acquire (); + for (j=0;j<refresh_session->num_newcoins;j++) + { + if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */ + ev_sigs[j] = refresh_exchange_coin (connection, + session, + session_hash, + key_state, + &denom_pubs[j], + &commit_coins[j], + j); + if (NULL == ev_sigs[j].rsa_signature) + { + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + } + TMH_KS_release (key_state); + COMMIT_TRANSACTION (session, connection); + return TMH_RESPONSE_reply_refresh_reveal_success (connection, + refresh_session->num_newcoins, + ev_sigs); +} + + +/** + * Execute a "/refresh/reveal". The client is revealing to us the + * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the + * revealed transfer keys would allow linkage to the blinded coins, + * and if so, return the signed coins for corresponding to the set of + * coins that was not chosen. + * + * @param connection the MHD connection to handle + * @param session_hash hash identifying the refresh session + * @param num_oldcoins size of y-dimension of @a transfer_privs array + * @param transfer_privs array with the revealed transfer keys, + * x-dimension must be #TALER_CNC_KAPPA - 1 + * @return MHD result code + */ +int +TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + unsigned int num_oldcoins, + struct TALER_TransferPrivateKeyP **transfer_privs) +{ + int res; + struct TALER_EXCHANGEDB_Session *session; + struct TALER_EXCHANGEDB_RefreshSession refresh_session; + struct TALER_EXCHANGEDB_RefreshMelt *melts; + struct TALER_DenominationPublicKey *denom_pubs; + struct TALER_DenominationSignature *ev_sigs; + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins; + unsigned int i; + unsigned int j; + unsigned int off; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + res = TMH_plugin->get_refresh_session (TMH_plugin->cls, + session, + session_hash, + &refresh_session); + if (GNUNET_NO == res) + return TMH_RESPONSE_reply_arg_invalid (connection, + "session_hash"); + if (GNUNET_SYSERR == res) + return TMH_RESPONSE_reply_internal_db_error (connection); + if (0 == refresh_session.num_oldcoins) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + + melts = GNUNET_malloc (refresh_session.num_oldcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshMelt)); + for (j=0;j<refresh_session.num_oldcoins;j++) + { + if (GNUNET_OK != + TMH_plugin->get_refresh_melt (TMH_plugin->cls, + session, + session_hash, + j, + &melts[j])) + { + GNUNET_break (0); + for (i=0;i<j;i++) + { + GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); + } + GNUNET_free (melts); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + } + denom_pubs = GNUNET_malloc (refresh_session.num_newcoins * + sizeof (struct TALER_DenominationPublicKey)); + if (GNUNET_OK != + TMH_plugin->get_refresh_order (TMH_plugin->cls, + session, + session_hash, + refresh_session.num_newcoins, + denom_pubs)) + { + GNUNET_break (0); + GNUNET_free (denom_pubs); + for (i=0;i<refresh_session.num_oldcoins;i++) + { + GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); + } + GNUNET_free (melts); + return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + + + off = 0; + for (i=0;i<TALER_CNC_KAPPA - 1;i++) + { + if (i == refresh_session.noreveal_index) + off = 1; + if (GNUNET_OK != + (res = check_commitment (connection, + session, + session_hash, + i + off, + refresh_session.num_oldcoins, + transfer_privs[i], + melts, + refresh_session.num_newcoins, + denom_pubs))) + { + for (j=0;j<refresh_session.num_newcoins;j++) + GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); + GNUNET_free (denom_pubs); + for (i=0;i<refresh_session.num_oldcoins;i++) + { + GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); + } + GNUNET_free (melts); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + } + for (i=0;i<refresh_session.num_oldcoins;i++) + { + GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); + } + GNUNET_free (melts); + + /* Client request OK, start transaction */ + commit_coins = GNUNET_malloc (refresh_session.num_newcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin)); + ev_sigs = GNUNET_malloc (refresh_session.num_newcoins * + sizeof (struct TALER_DenominationSignature)); + res = execute_refresh_reveal_transaction (connection, + session, + session_hash, + &refresh_session, + melts, + denom_pubs, + ev_sigs, + commit_coins); + for (i=0;i<refresh_session.num_newcoins;i++) + if (NULL != ev_sigs[i].rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); + for (j=0;j<refresh_session.num_newcoins;j++) + if (NULL != denom_pubs[j].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); + GNUNET_free (ev_sigs); + GNUNET_free (denom_pubs); + GNUNET_free (commit_coins); + return res; +} + + +/** + * Closure for #handle_transfer_data(). + */ +struct HTD_Context +{ + + /** + * Session link data we collect. + */ + struct TMH_RESPONSE_LinkSessionInfo *sessions; + + /** + * Database session. Nothing to do with @a sessions. + */ + struct TALER_EXCHANGEDB_Session *session; + + /** + * MHD connection, for queueing replies. + */ + struct MHD_Connection *connection; + + /** + * Number of sessions the coin was melted into. + */ + unsigned int num_sessions; + + /** + * How are we expected to proceed. #GNUNET_SYSERR if we + * failed to return an error (should return #MHD_NO). + * #GNUNET_NO if we succeeded in queueing an MHD error + * (should return #MHD_YES from #TMH_execute_refresh_link), + * #GNUNET_OK if we should call #TMH_RESPONSE_reply_refresh_link_success(). + */ + int status; +}; + + +/** + * Function called with the session hashes and transfer secret + * information for a given coin. Gets the linkage data and + * builds the reply for the client. + * + * + * @param cls closure, a `struct HTD_Context` + * @param session_hash a session the coin was melted in + * @param transfer_pub public transfer key for the session + * @param shared_secret_enc set to shared secret for the session + */ +static void +handle_transfer_data (void *cls, + const struct GNUNET_HashCode *session_hash, + const struct TALER_TransferPublicKeyP *transfer_pub, + const struct TALER_EncryptedLinkSecretP *shared_secret_enc) +{ + struct HTD_Context *ctx = cls; + struct TALER_EXCHANGEDB_LinkDataList *ldl; + struct TMH_RESPONSE_LinkSessionInfo *lsi; + + if (GNUNET_OK != ctx->status) + return; + ldl = TMH_plugin->get_link_data_list (TMH_plugin->cls, + ctx->session, + session_hash); + if (NULL == ldl) + { + ctx->status = GNUNET_NO; + if (MHD_NO == + TMH_RESPONSE_reply_json_pack (ctx->connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "link data not found (link)")) + ctx->status = GNUNET_SYSERR; + return; + } + GNUNET_array_grow (ctx->sessions, + ctx->num_sessions, + ctx->num_sessions + 1); + lsi = &ctx->sessions[ctx->num_sessions - 1]; + lsi->transfer_pub = *transfer_pub; + lsi->shared_secret_enc = *shared_secret_enc; + lsi->ldl = ldl; +} + + +/** + * Execute a "/refresh/link". Returns the linkage information that + * will allow the owner of a coin to follow the refresh trail to + * the refreshed coin. + * + * @param connection the MHD connection to handle + * @param coin_pub public key of the coin to link + * @return MHD result code + */ +int +TMH_DB_execute_refresh_link (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub) +{ + struct HTD_Context ctx; + int res; + unsigned int i; + + if (NULL == (ctx.session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + ctx.connection = connection; + ctx.num_sessions = 0; + ctx.sessions = NULL; + ctx.status = GNUNET_OK; + res = TMH_plugin->get_transfer (TMH_plugin->cls, + ctx.session, + coin_pub, + &handle_transfer_data, + &ctx); + if (GNUNET_SYSERR == ctx.status) + { + res = MHD_NO; + goto cleanup; + } + if (GNUNET_NO == ctx.status) + { + res = MHD_YES; + goto cleanup; + } + GNUNET_assert (GNUNET_OK == ctx.status); + if (0 == ctx.num_sessions) + return TMH_RESPONSE_reply_arg_unknown (connection, + "coin_pub"); + res = TMH_RESPONSE_reply_refresh_link_success (connection, + ctx.num_sessions, + ctx.sessions); + cleanup: + for (i=0;i<ctx.num_sessions;i++) + TMH_plugin->free_link_data_list (TMH_plugin->cls, + ctx.sessions[i].ldl); + GNUNET_free_non_null (ctx.sessions); + return res; +} + + +/** + * Add an incoming transaction to the database. Checks if the + * transaction is fresh (not a duplicate) and if so adds it to + * the database. + * + * @param connection the MHD connection to handle + * @param reserve_pub public key of the reserve + * @param amount amount to add to the reserve + * @param execution_time when did we receive the wire transfer + * @param wire details about the wire transfer + * @return MHD result code + */ +int +TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute execution_time, + json_t *wire) +{ + struct TALER_EXCHANGEDB_Session *session; + int ret; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + ret = TMH_plugin->reserves_in_insert (TMH_plugin->cls, + session, + reserve_pub, + amount, + execution_time, + wire); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s}", + "status", + (GNUNET_OK == ret) + ? "NEW" + : "DUP"); +} + + +/** + * Closure for #handle_transaction_data. + */ +struct WtidTransactionContext +{ + + /** + * Total amount of the wire transfer, as calculated by + * summing up the individual amounts. To be rounded down + * to calculate the real transfer amount at the end. + * Only valid if @e is_valid is #GNUNET_YES. + */ + struct TALER_Amount total; + + /** + * Public key of the merchant, only valid if @e is_valid + * is #GNUNET_YES. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash of the wire details of the merchant (identical for all + * deposits), only valid if @e is_valid is #GNUNET_YES. + */ + struct GNUNET_HashCode h_wire; + + /** + * JSON array with details about the individual deposits. + */ + json_t *deposits; + + /** + * Initially #GNUNET_NO, if we found no deposits so far. Set to + * #GNUNET_YES if we got transaction data, and the database replies + * remained consistent with respect to @e merchant_pub and @e h_wire + * (as they should). Set to #GNUNET_SYSERR if we encountered an + * internal error. + */ + int is_valid; + +}; + + +/** + * Function called with the results of the lookup of the + * transaction data for the given wire transfer identifier. + * + * @param cls our context for transmission + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param coin_pub which public key was this payment about + * @param deposit_value amount contributed by this coin in total + * @param deposit_fee deposit fee charged by exchange for this coin + */ +static void +handle_transaction_data (void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee) +{ + struct WtidTransactionContext *ctx = cls; + struct TALER_Amount delta; + + if (GNUNET_SYSERR == ctx->is_valid) + return; + if (GNUNET_NO == ctx->is_valid) + { + ctx->merchant_pub = *merchant_pub; + ctx->h_wire = *h_wire; + ctx->is_valid = GNUNET_YES; + if (GNUNET_OK != + TALER_amount_subtract (&ctx->total, + deposit_value, + deposit_fee)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + } + else + { + if ( (0 != memcmp (&ctx->merchant_pub, + merchant_pub, + sizeof (struct TALER_MerchantPublicKeyP))) || + (0 != memcmp (&ctx->h_wire, + h_wire, + sizeof (struct GNUNET_HashCode))) ) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + TALER_amount_subtract (&delta, + deposit_value, + deposit_fee)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + TALER_amount_add (&ctx->total, + &ctx->total, + &delta)) + { + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + } + /* NOTE: We usually keep JSON stuff out of the _DB file, and this + is also ugly if we ever add signatures over this data. (#4135) */ + json_array_append (ctx->deposits, + json_pack ("{s:o, s:o, s:o, s:I, s:o}", + "deposit_value", TALER_json_from_amount (deposit_value), + "deposit_fee", TALER_json_from_amount (deposit_fee), + "H_contract", TALER_json_from_data (h_contract, + sizeof (struct GNUNET_HashCode)), + "transaction_id", (json_int_t) transaction_id, + "coin_pub", TALER_json_from_data (coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)))); +} + + +/** + * Execute a "/wire/deposits". Returns the transaction information + * associated with the given wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param wtid wire transfer identifier to resolve + * @return MHD result code + */ +int +TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, + const struct TALER_WireTransferIdentifierRawP *wtid) +{ + int ret; + struct WtidTransactionContext ctx; + struct TALER_EXCHANGEDB_Session *session; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + ctx.is_valid = GNUNET_NO; + ctx.deposits = json_array (); + ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls, + session, + wtid, + &handle_transaction_data, + &ctx); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_SYSERR == ctx.is_valid) + { + GNUNET_break (0); + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_NO == ctx.is_valid) + { + json_decref (ctx.deposits); + return TMH_RESPONSE_reply_arg_unknown (connection, + "wtid"); + } + return TMH_RESPONSE_reply_wire_deposit_details (connection, + &ctx.total, + &ctx.merchant_pub, + &ctx.h_wire, + ctx.deposits); +} + + +/** + * Closure for #handle_wtid_data. + */ +struct DepositWtidContext +{ + + /** + * Where should we send the reply? + */ + struct MHD_Connection *connection; + + /** + * Hash of the contract we are looking up. + */ + struct GNUNET_HashCode h_contract; + + /** + * Hash of the wire transfer details we are looking up. + */ + struct GNUNET_HashCode h_wire; + + /** + * Public key we are looking up. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Transaction ID we are looking up. + */ + uint64_t transaction_id; + + /** + * MHD result code to return. + */ + int res; +}; + + +/** + * Function called with the results of the lookup of the + * wire transfer identifier information. + * + * @param cls our context for transmission + * @param wtid raw wire transfer identifier, NULL + * if the transaction was not yet done + * @param coin_contribution how much did the coin we asked about + * contribute to the total transfer value? (deposit value including fee) + * @param coin_fee how much did the exchange charge for the deposit fee + * @param execution_time when was the transaction done, or + * when we expect it to be done (if @a wtid was NULL); + * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown + * to the exchange + */ +static void +handle_wtid_data (void *cls, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_Amount *coin_contribution, + const struct TALER_Amount *coin_fee, + struct GNUNET_TIME_Absolute execution_time) +{ + struct DepositWtidContext *ctx = cls; + struct TALER_Amount coin_delta; + + if (NULL == wtid) + { + ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection, + execution_time); + } + else + { + if (GNUNET_SYSERR == + TALER_amount_subtract (&coin_delta, + coin_contribution, + coin_fee)) + { + GNUNET_break (0); + ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection); + } + else + { + ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection, + &ctx->h_contract, + &ctx->h_wire, + &ctx->coin_pub, + &coin_delta, + ctx->transaction_id, + wtid, + execution_time); + } + } +} + + +/** + * Execute a "/deposit/wtid". Returns the transfer information + * associated with the given deposit. + * + * @param connection the MHD connection to handle + * @param h_contract hash of the contract + * @param h_wire hash of the wire details + * @param coin_pub public key of the coin to link + * @param merchant_pub public key of the merchant + * @param transaction_id transaction ID of the merchant + * @return MHD result code + */ +int +TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id) +{ + int ret; + struct DepositWtidContext ctx; + struct TALER_EXCHANGEDB_Session *session; + + if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode))) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + ctx.connection = connection; + ctx.h_contract = *h_contract; + ctx.h_wire = *h_wire; + ctx.coin_pub = *coin_pub; + ctx.transaction_id = transaction_id; + ctx.res = GNUNET_SYSERR; + ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls, + session, + h_contract, + h_wire, + coin_pub, + merchant_pub, + transaction_id, + &handle_wtid_data, + &ctx); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + GNUNET_break (GNUNET_SYSERR == ctx.res); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + if (GNUNET_NO == ret) + { + GNUNET_break (GNUNET_SYSERR == ctx.res); + return TMH_RESPONSE_reply_deposit_unknown (connection); + } + if (GNUNET_SYSERR == ctx.res) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_error (connection, + "bug resolving deposit wtid"); + } + return ctx.res; +} + + +/* end of taler-exchange-httpd_db.c */ diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h new file mode 100644 index 000000000..d6245a702 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_db.h @@ -0,0 +1,230 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange/taler-exchange-httpd_db.h + * @brief High-level (transactional-layer) database operations for the exchange + * @author Chrisitan Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_DB_H +#define TALER_EXCHANGE_HTTPD_DB_H + +#include <microhttpd.h> +#include "taler_exchangedb_plugin.h" + + +/** + * Execute a "/deposit". The validity of the coin and signature + * have already been checked. The database must now check that + * the coin is not (double or over) spent, and execute the + * transaction (record details, generate success or failure response). + * + * @param connection the MHD connection to handle + * @param deposit information about the deposit + * @return MHD result code + */ +int +TMH_DB_execute_deposit (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_Deposit *deposit); + + +/** + * Execute a "/reserve/status". Given the public key of a reserve, + * return the associated transaction history. + * + * @param connection the MHD connection to handle + * @param reserve_pub public key of the reserve to check + * @return MHD result code + */ +int +TMH_DB_execute_reserve_status (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve_pub); + + +/** + * Execute a "/reserve/withdraw". Given a reserve and a properly signed + * request to withdraw a coin, check the balance of the reserve and + * if it is sufficient, store the request and return the signed + * blinded envelope. + * + * @param connection the MHD connection to handle + * @param reserve public key of the reserve + * @param denomination_pub public key of the denomination requested + * @param blinded_msg blinded message to be signed + * @param blinded_msg_len number of bytes in @a blinded_msg + * @param signature signature over the withdraw request, to be stored in DB + * @return MHD result code + */ +int +TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve, + const struct TALER_DenominationPublicKey *denomination_pub, + const char *blinded_msg, + size_t blinded_msg_len, + const struct TALER_ReserveSignatureP *signature); + + +/** + * @brief Details about a melt operation of an individual coin. + */ +struct TMH_DB_MeltDetails +{ + + /** + * Information about the coin being melted. + */ + struct TALER_CoinPublicInfo coin_info; + + /** + * Signature allowing the melt (using + * a `struct TALER_EXCHANGEDB_RefreshMeltConfirmSignRequestBody`) to sign over. + */ + struct TALER_CoinSpendSignatureP melt_sig; + + /** + * How much of the coin's value did the client allow to be melted? + * This amount includes the fees, so the final amount contributed + * to the melt is this value minus the fee for melting the coin. + */ + struct TALER_Amount melt_amount_with_fee; + + /** + * What fee is earned by the exchange? Set delayed during + * #verify_coin_public_info(). + */ + struct TALER_Amount melt_fee; +}; + + +/** + * Execute a "/refresh/melt". We have been given a list of valid + * coins and a request to melt them into the given + * @a refresh_session_pub. Check that the coins all have the + * required value left and if so, store that they have been + * melted and confirm the melting operation to the client. + * + * @param connection the MHD connection to handle + * @param session_hash hash code of the session the coins are melted into + * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array + * @param denom_pubs array of public denomination keys for the refresh (?) + * @param coin_count number of entries in @ a coin_melt_details, size of y-dimension of @a commit_link array + * @param coin_melt_details signatures and (residual) value of and information about the respective coin to be melted + * @param commit_coin 2d array of coin commitments (what the exchange is to sign + * once the "/refres/reveal" of cut and choose is done) + * @param commit_link 2d array of coin link commitments (what the exchange is + * to return via "/refresh/link" to enable linkage in the + * future) + * @return MHD result code + */ +int +TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + unsigned int num_new_denoms, + const struct TALER_DenominationPublicKey *denom_pubs, + unsigned int coin_count, + const struct TMH_DB_MeltDetails *coin_melt_details, + struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin, + struct TALER_RefreshCommitLinkP *const* commit_link); + + +/** + * Execute a "/refresh/reveal". The client is revealing to us the + * transfer keys for #TALER_CNC_KAPPA-1 sets of coins. Verify that the + * revealed transfer keys would allow linkage to the blinded coins, + * and if so, return the signed coins for corresponding to the set of + * coins that was not chosen. + * + * @param connection the MHD connection to handle + * @param session_hash hash over the refresh session + * @param num_oldcoins size of y-dimension of @a transfer_privs array + * @param transfer_privs array with the revealed transfer keys, #TALER_CNC_KAPPA is 1st-dimension + * @return MHD result code + */ +int +TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + unsigned int num_oldcoins, + struct TALER_TransferPrivateKeyP **transfer_privs); + + +/** + * Execute a "/refresh/link". Returns the linkage information that + * will allow the owner of a coin to follow the refresh trail to the + * refreshed coin. + * + * @param connection the MHD connection to handle + * @param coin_pub public key of the coin to link + * @return MHD result code + */ +int +TMH_DB_execute_refresh_link (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub); + + + +/** + * Add an incoming transaction to the database. + * + * @param connection the MHD connection to handle + * @param reserve_pub public key of the reserve + * @param amount amount to add to the reserve + * @param execution_time when did we receive the wire transfer + * @param wire details about the wire transfer + * @return MHD result code + */ +int +TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute execution_time, + json_t *wire); + + +/** + * Execute a "/wire/deposits". Returns the transaction information + * associated with the given wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param wtid wire transfer identifier to resolve + * @return MHD result code + */ +int +TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, + const struct TALER_WireTransferIdentifierRawP *wtid); + + +/** + * Execute a "/deposit/wtid". Returns the transfer information + * associated with the given deposit. + * + * @param connection the MHD connection to handle + * @param h_contract hash of the contract + * @param h_wire hash of the wire details + * @param coin_pub public key of the coin to link + * @param merchant_pub public key of the merchant + * @param transaction_id transaction ID of the merchant + * @return MHD result code + */ +int +TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id); + + +#endif +/* TALER_EXCHANGE_HTTPD_DB_H */ diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c new file mode 100644 index 000000000..629d6f8b5 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -0,0 +1,281 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_deposit.c + * @brief Handle /deposit requests; parses the POST and JSON and + * verifies the coin signature before handing things off + * to the database. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + * + * TODO: + * - ugly if-construction for deposit type + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_deposit.h" +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_keystate.h" +#include "taler-exchange-httpd_validation.h" + + +/** + * We have parsed the JSON information about the deposit, do some + * basic sanity checks (especially that the signature on the coin is + * valid, and that this type of coin exists) and then execute the + * deposit. + * + * @param connection the MHD connection to handle + * @param deposit information about the deposit + * @return MHD result code + */ +static int +verify_and_execute_deposit (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_Deposit *deposit) +{ + struct TMH_KS_StateHandle *key_state; + struct TALER_DepositRequestPS dr; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TALER_Amount fee_deposit; + + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); + dr.h_contract = deposit->h_contract; + dr.h_wire = deposit->h_wire; + dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); + dr.transaction_id = GNUNET_htonll (deposit->transaction_id); + TALER_amount_hton (&dr.amount_with_fee, + &deposit->amount_with_fee); + TALER_amount_hton (&dr.deposit_fee, + &deposit->deposit_fee); + dr.merchant = deposit->merchant_pub; + dr.coin_pub = deposit->coin.coin_pub; + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, + &dr.purpose, + &deposit->csig.eddsa_signature, + &deposit->coin.coin_pub.eddsa_pub)) + { + TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); + return TMH_RESPONSE_reply_signature_invalid (connection, + "coin_sig"); + } + /* check denomination exists and is valid */ + key_state = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (key_state, + &deposit->coin.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dki) + { + TMH_KS_release (key_state); + TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); + return TMH_RESPONSE_reply_arg_unknown (connection, + "denom_pub"); + } + /* check coin signature */ + if (GNUNET_YES != + TALER_test_coin_valid (&deposit->coin)) + { + TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_signature_invalid (connection, + "ub_sig"); + } + TALER_amount_ntoh (&fee_deposit, + &dki->issue.properties.fee_deposit); + if (0 < TALER_amount_cmp (&fee_deposit, + &deposit->amount_with_fee)) + { + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_external_error (connection, + "deposited amount smaller than depositing fee"); + } + TMH_KS_release (key_state); + + return TMH_DB_execute_deposit (connection, + deposit); +} + + +/** + * Handle a "/deposit" request. This function parses the + * JSON information and then calls #verify_and_execute_deposit() + * to verify the signatures and execute the deposit. + * + * @param connection the MHD connection to handle + * @param root root of the posted JSON + * @param amount how much should be deposited + * @param wire json describing the wire details (?) + * @return MHD result code + */ +static int +parse_and_handle_deposit_request (struct MHD_Connection *connection, + const json_t *root, + const struct TALER_Amount *amount, + json_t *wire) +{ + int res; + struct TALER_EXCHANGEDB_Deposit deposit; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TMH_KS_StateHandle *ks; + struct GNUNET_HashCode my_h_wire; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub), + TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig), + TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub), + TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub), + TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract), + TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire), + TMH_PARSE_member_fixed ("coin_sig", &deposit.csig), + TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id), + TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp), + TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline), + TMH_PARSE_member_time_abs ("edate", &deposit.wire_deadline), + TMH_PARSE_MEMBER_END + }; + + memset (&deposit, 0, sizeof (deposit)); + res = TMH_PARSE_json_data (connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == res) + return MHD_YES; /* failure */ + + if (GNUNET_YES != + TMH_json_validate_wireformat (wire)) + { + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_unknown (connection, + "wire"); + } + if (GNUNET_OK != + TALER_hash_json (wire, + &my_h_wire)) + { + TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n"); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_invalid (connection, + "wire"); + } + if (0 != memcmp (&deposit.h_wire, + &my_h_wire, + sizeof (struct GNUNET_HashCode))) + { + /* Client hashed contract differently than we did, reject */ + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_invalid (connection, + "H_wire"); + } + ks = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (ks, + &deposit.coin.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dki) + { + TMH_KS_release (ks); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_unknown (connection, + "denom_pub"); + } + TALER_amount_ntoh (&deposit.deposit_fee, + &dki->issue.properties.fee_deposit); + TMH_KS_release (ks); + deposit.wire = wire; + deposit.amount_with_fee = *amount; + if (-1 == TALER_amount_cmp (&deposit.amount_with_fee, + &deposit.deposit_fee)) + { + /* Total amount smaller than fee, invalid */ + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_invalid (connection, + "f"); + } + res = verify_and_execute_deposit (connection, + &deposit); + TMH_PARSE_release_data (spec); + return res; +} + + +/** + * Handle a "/deposit" request. Parses the JSON in the post to find + * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if + * successful, passes the JSON data to + * #parse_and_handle_deposit_request() to further check the details + * of the operation specified in the "wire" field of the JSON data. + * If everything checks out, this will ultimately lead to the + * "/deposit" being executed, or rejected. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + json_t *wire; + int res; + struct TALER_Amount amount; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_object ("wire", &wire), + TMH_PARSE_member_amount ("f", &amount), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + if (GNUNET_OK != res) + { + json_decref (json); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + res = parse_and_handle_deposit_request (connection, + json, + &amount, + wire); + TMH_PARSE_release_data (spec); + json_decref (json); + return res; +} + + +/* end of taler-exchange-httpd_deposit.c */ diff --git a/src/exchange/taler-exchange-httpd_deposit.h b/src/exchange/taler-exchange-httpd_deposit.h new file mode 100644 index 000000000..6e84573e5 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_deposit.h @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_deposit.h + * @brief Handle /deposit requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_DEPOSIT_H +#define TALER_EXCHANGE_HTTPD_DEPOSIT_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/deposit" request. Parses the JSON in the post to find + * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if + * successful, passes the JSON data to + * #parse_and_handle_deposit_request() to further check the details + * of the operation specified in the "wire" field of the JSON data. + * If everything checks out, this will ultimately lead to the + * "/deposit" being executed, or rejected. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + +#endif diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c new file mode 100644 index 000000000..e278882fe --- /dev/null +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -0,0 +1,1011 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_keystate.c + * @brief management of our coin signing keys + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <pthread.h> +#include "taler-exchange-httpd_keystate.h" +#include "taler-exchange-httpd_responses.h" +#include "taler_exchangedb_plugin.h" + + +/** + * Snapshot of the (coin and signing) keys (including private keys) of + * the exchange. There can be multiple instances of this struct, as it is + * reference counted and only destroyed once the last user is done + * with it. The current instance is acquired using + * #TMH_KS_acquire(). Using this function increases the + * reference count. The contents of this structure (except for the + * reference counter) should be considered READ-ONLY until it is + * ultimately destroyed (as there can be many concurrent users). + */ +struct TMH_KS_StateHandle +{ + /** + * JSON array with denomination keys. (Currently not really used + * after initialization.) + */ + json_t *denom_keys_array; + + /** + * JSON array with signing keys. (Currently not really used + * after initialization.) + */ + json_t *sign_keys_array; + + /** + * JSON array with auditor information. (Currently not really used + * after initialization.) + */ + json_t *auditors_array; + + /** + * Cached JSON text that the exchange will send for a "/keys" request. + * Includes our @e TMH_master_public_key public key, the signing and + * denomination keys as well as the @e reload_time. + */ + char *keys_json; + + /** + * Mapping from denomination keys to denomination key issue struct. + * Used to lookup the key by hash. + */ + struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; + + /** + * Hash context we used to combine the hashes of all denomination + * keys into one big hash. + */ + struct GNUNET_HashContext *hash_context; + + /** + * When did we initiate the key reloading? + */ + struct GNUNET_TIME_Absolute reload_time; + + /** + * When is the next key invalid and we have to reload? (We also + * reload on SIGUSR1.) + */ + struct GNUNET_TIME_Absolute next_reload; + + /** + * Exchange signing key that should be used currently. + */ + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP current_sign_key_issue; + + /** + * Reference count. The struct is released when the RC hits zero. + */ + unsigned int refcnt; +}; + + +/** + * Exchange key state. Never use directly, instead access via + * #TMH_KS_acquire() and #TMH_KS_release(). + */ +static struct TMH_KS_StateHandle *internal_key_state; + +/** + * Mutex protecting access to #internal_key_state. + */ +static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Pipe used for signaling reloading of our key state. + */ +static int reload_pipe[2]; + + +/** + * Convert the public part of a denomination key issue to a JSON + * object. + * + * @param pk public key of the denomination key + * @param dki the denomination key issue + * @return a JSON object describing the denomination key isue (public part) + */ +static json_t * +denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk, + const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki) +{ + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + struct TALER_Amount fee_deposit; + struct TALER_Amount fee_refresh; + + TALER_amount_ntoh (&value, + &dki->properties.value); + TALER_amount_ntoh (&fee_withdraw, + &dki->properties.fee_withdraw); + TALER_amount_ntoh (&fee_deposit, + &dki->properties.fee_deposit); + TALER_amount_ntoh (&fee_refresh, + &dki->properties.fee_refresh); + return + json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", + "master_sig", + TALER_json_from_data (&dki->signature, + sizeof (struct GNUNET_CRYPTO_EddsaSignature)), + "stamp_start", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)), + "stamp_expire_withdraw", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)), + "stamp_expire_deposit", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)), + "stamp_expire_legal", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)), + "denom_pub", + TALER_json_from_rsa_public_key (pk->rsa_public_key), + "value", + TALER_json_from_amount (&value), + "fee_withdraw", + TALER_json_from_amount (&fee_withdraw), + "fee_deposit", + TALER_json_from_amount (&fee_deposit), + "fee_refresh", + TALER_json_from_amount (&fee_refresh)); +} + + +/** + * Get the relative time value that describes how + * far in the future do we want to provide coin keys. + * + * @return the provide duration + */ +static struct GNUNET_TIME_Relative +TALER_EXCHANGE_conf_duration_provide () +{ + struct GNUNET_TIME_Relative rel; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, + "exchange_keys", + "lookahead_provide", + &rel)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange_keys", + "lookahead_provide", + "time value required"); + GNUNET_assert (0); + } + return rel; +} + + +/** + * Iterator for (re)loading/initializing denomination keys. + * + * @param cls closure + * @param dki the denomination key issue + * @param alias coin alias + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +reload_keys_denom_iter (void *cls, + const char *alias, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + struct TMH_KS_StateHandle *ctx = cls; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute horizon; + struct GNUNET_HashCode denom_key_hash; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *d2; + struct TALER_EXCHANGEDB_Session *session; + int res; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Loading denomination key `%s'\n", + alias); + horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ()); + if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us > + horizon.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping future denomination key `%s'\n", + alias); + return GNUNET_OK; + } + now = GNUNET_TIME_absolute_get (); + if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us < + now.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping expired denomination key `%s'\n", + alias); + return GNUNET_OK; + } + + GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key, + &denom_key_hash); + GNUNET_CRYPTO_hash_context_read (ctx->hash_context, + &denom_key_hash, + sizeof (struct GNUNET_HashCode)); + session = TMH_plugin->get_session (TMH_plugin->cls, + TMH_test_mode); + if (NULL == session) + return GNUNET_SYSERR; + /* Try to insert DKI into DB until we succeed; note that if the DB + failure is persistent, this code may loop forever (as there is no + sane alternative, we cannot continue without the DKI being in the + DB). */ + res = GNUNET_SYSERR; + while (GNUNET_OK != res) + { + res = TMH_plugin->start (TMH_plugin->cls, + session); + if (GNUNET_OK != res) + { + /* Transaction start failed!? Very bad error, log and retry */ + GNUNET_break (0); + continue; + } + res = TMH_plugin->get_denomination_info (TMH_plugin->cls, + session, + &dki->denom_pub, + NULL); + if (GNUNET_SYSERR == res) + { + /* Fetch failed!? Very bad error, log and retry */ + GNUNET_break (0); + TMH_plugin->rollback (TMH_plugin->cls, + session); + continue; + } + if (GNUNET_OK == res) + { + /* Record exists, we're good, just exit */ + TMH_plugin->rollback (TMH_plugin->cls, + session); + break; + } + res = TMH_plugin->insert_denomination_info (TMH_plugin->cls, + session, + &dki->denom_pub, + &dki->issue); + if (GNUNET_OK != res) + { + /* Insert failed!? Very bad error, log and retry */ + GNUNET_break (0); + TMH_plugin->rollback (TMH_plugin->cls, + session); + continue; + } + res = TMH_plugin->commit (TMH_plugin->cls, + session); + /* If commit succeeded, we're done, otherwise we retry; this + time without logging, as theroetically commits can fail + in a transactional DB due to concurrent activities that + cannot be reconciled. This should be rare for DKIs, but + as it is possible we just retry until we succeed. */ + } + + d2 = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation); + d2->issue = dki->issue; + d2->denom_priv.rsa_private_key + = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key); + d2->denom_pub.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); + res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map, + &denom_key_hash, + d2, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + if (GNUNET_OK != res) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Duplicate denomination key `%s'\n", + alias); + GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key); + GNUNET_free (d2); + return GNUNET_OK; + } + json_array_append_new (ctx->denom_keys_array, + denom_key_issue_to_json (&dki->denom_pub, + &dki->issue)); + return GNUNET_OK; +} + + +/** + * Convert the public part of a sign key issue to a JSON object. + * + * @param ski the sign key issue + * @return a JSON object describing the sign key issue (public part) + */ +static json_t * +sign_key_issue_to_json (const struct TALER_ExchangeSigningKeyValidityPS *ski) +{ + return + json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", + "stamp_start", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)), + "stamp_expire", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)), + "stamp_end", + TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->end)), + "master_pub", + TALER_json_from_data (&ski->master_public_key, + sizeof (struct TALER_MasterPublicKeyP)), + "master_sig", + TALER_json_from_data (&ski->signature, + sizeof (struct TALER_MasterSignatureP)), + "key", + TALER_json_from_data (&ski->signkey_pub, + sizeof (struct TALER_ExchangePublicKeyP))); +} + + +/** + * Iterator for sign keys. + * + * @param cls closure with the `struct TMH_KS_StateHandle *` + * @param filename name of the file the key came from + * @param ski the sign key issue + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +reload_keys_sign_iter (void *cls, + const char *filename, + const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski) +{ + struct TMH_KS_StateHandle *ctx = cls; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute horizon; + + horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ()); + if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us > + horizon.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping future signing key `%s'\n", + filename); + return GNUNET_OK; + } + now = GNUNET_TIME_absolute_get (); + if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us < + now.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping expired signing key `%s'\n", + filename); + return GNUNET_OK; + } + + /* The signkey is valid at this time, check if it's more recent than + what we have so far! */ + if ( (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us < + GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) && + (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us < + now.abs_value_us) ) + { + /* We use the most recent one, if it is valid now (not just in the near future) */ + ctx->current_sign_key_issue = *ski; + } + json_array_append_new (ctx->sign_keys_array, + sign_key_issue_to_json (&ski->issue)); + + return GNUNET_OK; +} + + +/** + * Convert information from an auditor to a JSON object. + * + * @param apub the auditor's public key + * @param dki_len length of @a dki and @a asigs arrays + * @param asigs the auditor's signatures + * @param dki array of denomination coin data signed by the auditor + * @return a JSON object describing the auditor information and signature + */ +static json_t * +auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, + unsigned int dki_len, + const struct TALER_AuditorSignatureP **asigs, + const struct TALER_DenominationKeyValidityPS **dki) +{ + unsigned int i; + json_t *ja; + + ja = json_array (); + for (i=0;i<dki_len;i++) + json_array_append_new (ja, + json_pack ("{s:o, s:o}", + "denom_pub_h", + TALER_json_from_data (&dki[i]->denom_hash, + sizeof (struct GNUNET_HashCode)), + "auditor_sig", + TALER_json_from_data (asigs[i], + sizeof (struct TALER_AuditorSignatureP)))); + return + json_pack ("{s:o, s:o}", + "denomination_keys", ja, + "auditor_pub", + TALER_json_from_data (apub, + sizeof (struct TALER_AuditorPublicKeyP))); +} + + +/** + * @brief Iterator called with auditor information. + * Check that the @a mpub actually matches this exchange, and then + * add the auditor information to our /keys response (if it is + * (still) applicable). + * + * @param cls closure with the `struct TMH_KS_StateHandle *` + * @param apub the auditor's public key + * @param mpub the exchange's public key (as expected by the auditor) + * @param dki_len length of @a dki and @a asigs + * @param asigs array with the auditor's signatures, of length @a dki_len + * @param dki array of denomination coin data signed by the auditor + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +reload_auditor_iter (void *cls, + const struct TALER_AuditorPublicKeyP *apub, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_DenominationKeyValidityPS *dki) +{ + struct TMH_KS_StateHandle *ctx = cls; + unsigned int i; + unsigned int keep; + const struct TALER_AuditorSignatureP *kept_asigs[dki_len]; + const struct TALER_DenominationKeyValidityPS *kept_dkis[dki_len]; + + /* Check if the signature is at least for this exchange. */ + if (0 != memcmp (&mpub->eddsa_pub, + &TMH_master_public_key, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Auditing information provided for a different exchange, ignored\n"); + return GNUNET_OK; + } + /* Filter the auditor information for those for which the + keys actually match the denomination keys that are active right now */ + keep = 0; + for (i=0;i<dki_len;i++) + { + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (ctx->denomkey_map, + &dki[i].denom_hash)) + { + kept_asigs[keep] = &asigs[i]; + kept_dkis[keep] = &dki[i]; + keep++; + } + } + /* add auditor information to our /keys response */ + json_array_append_new (ctx->auditors_array, + auditor_to_json (apub, + keep, + kept_asigs, + kept_dkis)); + return GNUNET_OK; +} + + +/** + * Iterator for freeing denomination keys. + * + * @param cls closure with the `struct TMH_KS_StateHandle` + * @param key key for the denomination key + * @param value coin details + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +free_denom_key (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = value; + + GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key); + GNUNET_free (dki); + return GNUNET_OK; +} + + +/** + * Release key state, free if necessary (if reference count gets to zero). + * Internal method used when the mutex is already held. + * + * @param key_state the key state to release + */ +static void +ks_release_ (struct TMH_KS_StateHandle *key_state) +{ + GNUNET_assert (0 < key_state->refcnt); + key_state->refcnt--; + if (0 == key_state->refcnt) + { + if (NULL != key_state->denom_keys_array) + { + json_decref (key_state->denom_keys_array); + key_state->denom_keys_array = NULL; + } + if (NULL != key_state->sign_keys_array) + { + json_decref (key_state->sign_keys_array); + key_state->sign_keys_array = NULL; + } + if (NULL != key_state->denomkey_map) + { + GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map, + &free_denom_key, + key_state); + GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map); + key_state->denomkey_map = NULL; + } + GNUNET_free_non_null (key_state->keys_json); + GNUNET_free (key_state); + } +} + + +/** + * Release key state, free if necessary (if reference count gets to zero). + * + * @param location name of the function in which the lock is acquired + * @param key_state the key state to release + */ +void +TMH_KS_release_ (const char *location, + struct TMH_KS_StateHandle *key_state) +{ + GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); + ks_release_ (key_state); + GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); +} + + +/** + * Acquire the key state of the exchange. Updates keys if necessary. + * For every call to #TMH_KS_acquire(), a matching call + * to #TMH_KS_release() must be made. + * + * @param location name of the function in which the lock is acquired + * @return the key state + */ +struct TMH_KS_StateHandle * +TMH_KS_acquire_ (const char *location) +{ + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct TMH_KS_StateHandle *key_state; + json_t *keys; + struct TALER_ExchangeKeySetPS ks; + struct TALER_ExchangeSignatureP sig; + + GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); + if ( (NULL != internal_key_state) && + (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) ) + { + ks_release_ (internal_key_state); + internal_key_state = NULL; + } + if (NULL == internal_key_state) + { + key_state = GNUNET_new (struct TMH_KS_StateHandle); + key_state->hash_context = GNUNET_CRYPTO_hash_context_start (); + + + key_state->denom_keys_array = json_array (); + GNUNET_assert (NULL != key_state->denom_keys_array); + + key_state->sign_keys_array = json_array (); + GNUNET_assert (NULL != key_state->sign_keys_array); + + key_state->auditors_array = json_array (); + GNUNET_assert (NULL != key_state->auditors_array); + + key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32, + GNUNET_NO); + key_state->reload_time = GNUNET_TIME_absolute_get (); + TALER_round_abs_time (&key_state->reload_time); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Loading keys from `%s'\n", + TMH_exchange_directory); + TALER_EXCHANGEDB_denomination_keys_iterate (TMH_exchange_directory, + &reload_keys_denom_iter, + key_state); + TALER_EXCHANGEDB_signing_keys_iterate (TMH_exchange_directory, + &reload_keys_sign_iter, + key_state); + TALER_EXCHANGEDB_auditor_iterate (TMH_exchange_directory, + &reload_auditor_iter, + key_state); + ks.purpose.size = htonl (sizeof (ks)); + ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET); + ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time); + GNUNET_CRYPTO_hash_context_finish (key_state->hash_context, + &ks.hc); + key_state->hash_context = NULL; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, + &ks.purpose, + &sig.eddsa_signature)); + key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire); + if (0 == key_state->next_reload.abs_value_us) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid signing key found!\n"); + + keys = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o}", + "master_public_key", + TALER_json_from_data (&TMH_master_public_key, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)), + "signkeys", key_state->sign_keys_array, + "denoms", key_state->denom_keys_array, + "auditors", key_state->auditors_array, + "list_issue_date", TALER_json_from_abs (key_state->reload_time), + "eddsa_pub", TALER_json_from_data (&key_state->current_sign_key_issue.issue.signkey_pub, + sizeof (struct TALER_ExchangePublicKeyP)), + "eddsa_sig", TALER_json_from_data (&sig, + sizeof (struct TALER_ExchangeSignatureP))); + key_state->auditors_array = NULL; + key_state->sign_keys_array = NULL; + key_state->denom_keys_array = NULL; + key_state->keys_json = json_dumps (keys, + JSON_INDENT (2)); + json_decref (keys); + internal_key_state = key_state; + } + key_state = internal_key_state; + key_state->refcnt++; + GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); + + return key_state; +} + + +/** + * Look up the issue for a denom public key. + * + * @param key_state state to look in + * @param denom_pub denomination public key + * @param use purpose for which the key is being located + * @return the denomination key issue, + * or NULL if denom_pub could not be found + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, + const struct TALER_DenominationPublicKey *denom_pub, + enum TMH_KS_DenominationKeyUse use) +{ + struct GNUNET_HashCode hc; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct GNUNET_TIME_Absolute now; + + GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key, + &hc); + dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map, + &hc); + if (NULL == dki) + return NULL; + now = GNUNET_TIME_absolute_get (); + if (now.abs_value_us < + GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Not returning DKI for %s, as start time is in the future\n", + GNUNET_h2s (&hc)); + return NULL; + } + now = GNUNET_TIME_absolute_get (); + switch (use) + { + case TMH_KS_DKU_WITHDRAW: + if (now.abs_value_us > + GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Not returning DKI for %s, as time to create coins has passed\n", + GNUNET_h2s (&hc)); + return NULL; + } + break; + case TMH_KS_DKU_DEPOSIT: + if (now.abs_value_us > + GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Not returning DKI for %s, as time to spend coin has passed\n", + GNUNET_h2s (&hc)); + return NULL; + } + break; + } + return dki; +} + + +/** + * Handle a signal, writing relevant signal numbers to the pipe. + * + * @param signal_number the signal number + */ +static void +handle_signal (int signal_number) +{ + ssize_t res; + char c = signal_number; + + res = write (reload_pipe[1], + &c, + 1); + if ( (res < 0) && + (EINTR != errno) ) + { + GNUNET_break (0); + return; + } + if (0 == res) + { + GNUNET_break (0); + return; + } +} + + +/** + * Call #handle_signal() to pass the received signal via + * the control pipe. + */ +static void +handle_sigusr1 () +{ + handle_signal (SIGUSR1); +} + + +/** + * Call #handle_signal() to pass the received signal via + * the control pipe. + */ +static void +handle_sigint () +{ + handle_signal (SIGINT); +} + + +/** + * Call #handle_signal() to pass the received signal via + * the control pipe. + */ +static void +handle_sigterm () +{ + handle_signal (SIGTERM); +} + + +/** + * Call #handle_signal() to pass the received signal via + * the control pipe. + */ +static void +handle_sighup () +{ + handle_signal (SIGHUP); +} + + +/** + * Call #handle_signal() to pass the received signal via + * the control pipe. + */ +static void +handle_sigchld () +{ + handle_signal (SIGCHLD); +} + + +/** + * Read signals from a pipe in a loop, and reload keys from disk if + * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and + * restart if SIGHUP is received. + * + * @return #GNUNET_SYSERR on errors, + * #GNUNET_OK to terminate normally + * #GNUNET_NO to restart an update version of the binary + */ +int +TMH_KS_loop (void) +{ + struct GNUNET_SIGNAL_Context *sigusr1; + struct GNUNET_SIGNAL_Context *sigterm; + struct GNUNET_SIGNAL_Context *sigint; + struct GNUNET_SIGNAL_Context *sighup; + struct GNUNET_SIGNAL_Context *sigchld; + int ret; + + if (0 != pipe (reload_pipe)) + { + fprintf (stderr, + "Failed to create pipe.\n"); + return GNUNET_SYSERR; + } + sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1, + &handle_sigusr1); + sigterm = GNUNET_SIGNAL_handler_install (SIGTERM, + &handle_sigterm); + sigint = GNUNET_SIGNAL_handler_install (SIGINT, + &handle_sigint); + sighup = GNUNET_SIGNAL_handler_install (SIGHUP, + &handle_sighup); + sigchld = GNUNET_SIGNAL_handler_install (SIGCHLD, + &handle_sigchld); + + ret = 0; + while (0 == ret) + { + char c; + ssize_t res; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "(re-)loading keys\n"); + if (NULL != internal_key_state) + { + TMH_KS_release (internal_key_state); + internal_key_state = NULL; + } + /* This will re-initialize 'internal_key_state' with + an initial refcnt of 1 */ + (void) TMH_KS_acquire (); + +read_again: + errno = 0; + res = read (reload_pipe[0], + &c, + 1); + if ((res < 0) && (EINTR != errno)) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + break; + } + if (EINTR == errno) + goto read_again; + switch (c) + { + case SIGUSR1: + /* reload internal key state, we do this in the loop */ + break; + case SIGTERM: + case SIGINT: + /* terminate */ + ret = GNUNET_OK; + break; + case SIGHUP: + /* restart updated binary */ + ret = GNUNET_NO; + break; +#if HAVE_DEVELOPER + case SIGCHLD: + /* running in test-mode, test finished, terminate */ + ret = GNUNET_OK; + break; +#endif + default: + /* unexpected character */ + GNUNET_break (0); + break; + } + } + if (NULL != internal_key_state) + { + TMH_KS_release (internal_key_state); + internal_key_state = NULL; + } + GNUNET_SIGNAL_handler_uninstall (sigusr1); + GNUNET_SIGNAL_handler_uninstall (sigterm); + GNUNET_SIGNAL_handler_uninstall (sigint); + GNUNET_SIGNAL_handler_uninstall (sighup); + GNUNET_SIGNAL_handler_uninstall (sigchld); + return ret; +} + + +/** + * Sign the message in @a purpose with the exchange's signing key. + * + * @param purpose the message to sign + * @param[out] pub set to the current public signing key of the exchange + * @param[out] sig signature over purpose using current signing key + */ +void +TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) + +{ + struct TMH_KS_StateHandle *key_state; + + key_state = TMH_KS_acquire (); + *pub = key_state->current_sign_key_issue.issue.signkey_pub; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, + purpose, + &sig->eddsa_signature)); + TMH_KS_release (key_state); +} + + +/** + * Function to call to handle the request by sending + * back static data from the @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_KS_handler_keys (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TMH_KS_StateHandle *key_state; + struct MHD_Response *response; + int ret; + + key_state = TMH_KS_acquire (); + response = MHD_create_response_from_buffer (strlen (key_state->keys_json), + key_state->keys_json, + MHD_RESPMEM_MUST_COPY); + TMH_KS_release (key_state); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (response); + (void) MHD_add_response_header (response, + "Content-Type", + rh->mime_type); + ret = MHD_queue_response (connection, + rh->response_code, + response); + MHD_destroy_response (response); + return ret; +} + + +/* end of taler-exchange-httpd_keystate.c */ diff --git a/src/exchange/taler-exchange-httpd_keystate.h b/src/exchange/taler-exchange-httpd_keystate.h new file mode 100644 index 000000000..56151a878 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_keystate.h @@ -0,0 +1,163 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange/taler-exchange-httpd_keystate.h + * @brief management of our private signing keys (denomination keys) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_KEYSTATE_H +#define TALER_EXCHANGE_HTTPD_KEYSTATE_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" +#include "taler_exchangedb_lib.h" + + +/** + * Snapshot of the (coin and signing) + * keys (including private keys) of the exchange. + */ +struct TMH_KS_StateHandle; + + +/** + * Acquire the key state of the exchange. Updates keys if necessary. + * For every call to #TMH_KS_acquire(), a matching call + * to #TMH_KS_release() must be made. + * + * @param location name of the function in which the lock is acquired + * @return the key state + */ +struct TMH_KS_StateHandle * +TMH_KS_acquire_ (const char *location); + + +/** + * Release key state, free if necessary (if reference count gets to zero). + * + * @param location name of the function in which the lock is acquired + * @param key_state the key state to release + */ +void +TMH_KS_release_ (const char *location, + struct TMH_KS_StateHandle *key_state); + + +/** + * Acquire the key state of the exchange. Updates keys if necessary. + * For every call to #TMH_KS_acquire(), a matching call + * to #TMH_KS_release() must be made. + * + * @return the key state + */ +#define TMH_KS_acquire(void) TMH_KS_acquire_(__FUNCTION__) + + +/** + * Release key state, free if necessary (if reference count gets to zero). + * + * @param key_state the key state to release + */ +#define TMH_KS_release(key_state) TMH_KS_release_ (__FUNCTION__, key_state) + + +/** + * Denomination key lookups can be for signing of fresh coins + * or to validate signatures on existing coins. As the validity + * periods for a key differ, the caller must specify which + * use is relevant for the current operation. + */ +enum TMH_KS_DenominationKeyUse { + + /** + * The key is to be used for a /reserve/withdraw or /refresh (exchange) + * operation. + */ + TMH_KS_DKU_WITHDRAW, + + /** + * The key is to be usd for a /deposit or /refresh (melt) operation. + */ + TMH_KS_DKU_DEPOSIT + +}; + + +/** + * Look up the issue for a denom public key. Note that the result + * is only valid while the @a key_state is not released! + * + * @param key_state state to look in + * @param denom_pub denomination public key + * @param use purpose for which the key is being located + * @return the denomination key issue, + * or NULL if denom_pub could not be found (or is not valid at this time for the given @a use) + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, + const struct TALER_DenominationPublicKey *denom_pub, + enum TMH_KS_DenominationKeyUse use); + + +/** + * Read signals from a pipe in a loop, and reload keys from disk if + * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and + * restart if SIGHUP is received. + * + * @return #GNUNET_SYSERR on errors, + * #GNUNET_OK to terminate normally + * #GNUNET_NO to restart an update version of the binary + */ +int +TMH_KS_loop (void); + + +/** + * Sign the message in @a purpose with the exchange's signing + * key. + * + * @param purpose the message to sign + * @param[out] pub set to the current public signing key of the exchange + * @param[out] sig signature over purpose using current signing key + */ +void +TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig); + + +/** + * Handle a "/keys" request + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_KS_handler_keys (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_mhd.c b/src/exchange/taler-exchange-httpd_mhd.c new file mode 100644 index 000000000..b7ad437aa --- /dev/null +++ b/src/exchange/taler-exchange-httpd_mhd.c @@ -0,0 +1,152 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_mhd.c + * @brief helpers for MHD interaction; these are TALER_EXCHANGE_handler_ functions + * that generate simple MHD replies that do not require any real operations + * to be performed (error handling, static pages, etc.) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd.h" +#include "taler-exchange-httpd_mhd.h" + +/** + * Function to call to handle the request by sending + * back static data from the @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct MHD_Response *response; + int ret; + + if (0 == rh->data_size) + rh->data_size = strlen ((const char *) rh->data); + response = MHD_create_response_from_buffer (rh->data_size, + (void *) rh->data, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (response); + if (NULL != rh->mime_type) + (void) MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + rh->mime_type); + ret = MHD_queue_response (connection, + rh->response_code, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Function to call to handle the request by sending + * back a redirect to the AGPL source code. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + const char *agpl = + "This server is licensed under the Affero GPL. You will now be redirected to the source code."; + struct MHD_Response *response; + int ret; + + response = MHD_create_response_from_buffer (strlen (agpl), + (void *) agpl, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (response); + if (NULL != rh->mime_type) + (void) MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + rh->mime_type); + MHD_add_response_header (response, + MHD_HTTP_HEADER_LOCATION, + "http://www.git.taler.net/?p=exchange.git"); + ret = MHD_queue_response (connection, + rh->response_code, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Function to call to handle the request by building a JSON + * reply with an error message from @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + return TMH_RESPONSE_reply_json_pack (connection, + rh->response_code, + "{s:s}", + "error", + rh->data); +} + + +/* end of taler-exchange-httpd_mhd.c */ diff --git a/src/exchange/taler-exchange-httpd_mhd.h b/src/exchange/taler-exchange-httpd_mhd.h new file mode 100644 index 000000000..3e825c559 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_mhd.h @@ -0,0 +1,111 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_mhd.h + * @brief helpers for MHD interaction, used to generate simple responses + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_MHD_H +#define TALER_EXCHANGE_HTTPD_MHD_H +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Function to call to handle the request by sending + * back static data from the @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Function to call to handle the request by sending + * back a redirect to the AGPL source code. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Function to call to handle the request by building a JSON + * reply from varargs. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param response_code HTTP response code to use + * @param do_cache can the response be cached? (0: no, 1: yes) + * @param fmt format string for pack + * @param ... varargs + * @return MHD result code + */ +int +TMH_MHD_helper_send_json_pack (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void *connection_cls, + int response_code, + int do_cache, + const char *fmt, + ...); + + +/** + * Function to call to handle the request by building a JSON + * reply with an error message from @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_parsing.c b/src/exchange/taler-exchange-httpd_parsing.c new file mode 100644 index 000000000..25539aeb7 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_parsing.c @@ -0,0 +1,1137 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_parsing.c + * @brief functions to parse incoming requests (MHD arguments and JSON snippets) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_responses.h" + + +/** + * Initial size for POST request buffer. + */ +#define REQUEST_BUFFER_INITIAL (2*1024) + +/** + * Maximum POST request size. + */ +#define REQUEST_BUFFER_MAX (1024*1024) + + +/** + * Buffer for POST requests. + */ +struct Buffer +{ + /** + * Allocated memory + */ + char *data; + + /** + * Number of valid bytes in buffer. + */ + size_t fill; + + /** + * Number of allocated bytes in buffer. + */ + size_t alloc; +}; + + +/** + * Initialize a buffer. + * + * @param buf the buffer to initialize + * @param data the initial data + * @param data_size size of the initial data + * @param alloc_size size of the buffer + * @param max_size maximum size that the buffer can grow to + * @return a GNUnet result code + */ +static int +buffer_init (struct Buffer *buf, + const void *data, + size_t data_size, + size_t alloc_size, + size_t max_size) +{ + if (data_size > max_size || alloc_size > max_size) + return GNUNET_SYSERR; + if (data_size > alloc_size) + alloc_size = data_size; + buf->data = GNUNET_malloc (alloc_size); + memcpy (buf->data, data, data_size); + return GNUNET_OK; +} + + +/** + * Free the data in a buffer. Does *not* free + * the buffer object itself. + * + * @param buf buffer to de-initialize + */ +static void +buffer_deinit (struct Buffer *buf) +{ + GNUNET_free (buf->data); + buf->data = NULL; +} + + +/** + * Append data to a buffer, growing the buffer if necessary. + * + * @param buf the buffer to append to + * @param data the data to append + * @param data_size the size of @a data + * @param max_size maximum size that the buffer can grow to + * @return #GNUNET_OK on success, + * #GNUNET_NO if the buffer can't accomodate for the new data + */ +static int +buffer_append (struct Buffer *buf, + const void *data, + size_t data_size, + size_t max_size) +{ + if (buf->fill + data_size > max_size) + return GNUNET_NO; + if (data_size + buf->fill > buf->alloc) + { + char *new_buf; + size_t new_size = buf->alloc; + while (new_size < buf->fill + data_size) + new_size += 2; + if (new_size > max_size) + return GNUNET_NO; + new_buf = GNUNET_malloc (new_size); + memcpy (new_buf, buf->data, buf->fill); + GNUNET_free (buf->data); + buf->data = new_buf; + buf->alloc = new_size; + } + memcpy (buf->data + buf->fill, data, data_size); + buf->fill += data_size; + return GNUNET_OK; +} + + +/** + * Release all memory allocated for the variable-size fields in + * the parser specification. + * + * @param spec specification to free + * @param spec_len number of items in @a spec to look at + */ +static void +release_data (struct TMH_PARSE_FieldSpecification *spec, + unsigned int spec_len) +{ + unsigned int i; + + for (i=0; i < spec_len; i++) + { + switch (spec[i].command) + { + case TMH_PARSE_JNC_FIELD: + GNUNET_break (0); + return; + case TMH_PARSE_JNC_INDEX: + GNUNET_break (0); + return; + case TMH_PARSE_JNC_RET_DATA: + break; + case TMH_PARSE_JNC_RET_DATA_VAR: + if (NULL != spec[i].destination) + { + GNUNET_free (* (void**) spec[i].destination); + *(void**) spec[i].destination = NULL; + *spec[i].destination_size_out = 0; + } + break; + case TMH_PARSE_JNC_RET_TYPED_JSON: + { + json_t *json; + + json = *(json_t **) spec[i].destination; + if (NULL != json) + { + json_decref (json); + *(json_t**) spec[i].destination = NULL; + } + } + break; + case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: + { + struct TALER_DenominationPublicKey *pk; + + pk = spec[i].destination; + if (NULL != pk->rsa_public_key) + { + GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key); + pk->rsa_public_key = NULL; + } + } + break; + case TMH_PARSE_JNC_RET_RSA_SIGNATURE: + { + struct TALER_DenominationSignature *sig; + + sig = spec[i].destination; + if (NULL != sig->rsa_signature) + { + GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature); + sig->rsa_signature = NULL; + } + } + break; + case TMH_PARSE_JNC_RET_AMOUNT: + memset (spec[i].destination, + 0, + sizeof (struct TALER_Amount)); + break; + case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: + break; + case TMH_PARSE_JNC_RET_UINT64: + break; + } + } +} + + +/** + * Process a POST request containing a JSON object. This function + * realizes an MHD POST processor that will (incrementally) process + * JSON data uploaded to the HTTP server. It will store the required + * state in the @a con_cls, which must be cleaned up using + * #TMH_PARSE_post_cleanup_callback(). + * + * @param connection the MHD connection + * @param con_cls the closure (points to a `struct Buffer *`) + * @param upload_data the POST data + * @param upload_data_size number of bytes in @a upload_data + * @param json the JSON object for a completed request + * @return + * #GNUNET_YES if json object was parsed or at least + * may be parsed in the future (call again); + * `*json` will be NULL if we need to be called again, + * and non-NULL if we are done. + * #GNUNET_NO is request incomplete or invalid + * (error message was generated) + * #GNUNET_SYSERR on internal error + * (we could not even queue an error message, + * close HTTP session with MHD_NO) + */ +int +TMH_PARSE_post_json (struct MHD_Connection *connection, + void **con_cls, + const char *upload_data, + size_t *upload_data_size, + json_t **json) +{ + struct Buffer *r = *con_cls; + + *json = NULL; + if (NULL == *con_cls) + { + /* We are seeing a fresh POST request. */ + r = GNUNET_new (struct Buffer); + if (GNUNET_OK != + buffer_init (r, + upload_data, + *upload_data_size, + REQUEST_BUFFER_INITIAL, + REQUEST_BUFFER_MAX)) + { + *con_cls = NULL; + buffer_deinit (r); + GNUNET_free (r); + return (MHD_NO == + TMH_RESPONSE_reply_internal_error (connection, + "out of memory")) + ? GNUNET_SYSERR : GNUNET_NO; + } + /* everything OK, wait for more POST data */ + *upload_data_size = 0; + *con_cls = r; + return GNUNET_YES; + } + if (0 != *upload_data_size) + { + /* We are seeing an old request with more data available. */ + + if (GNUNET_OK != + buffer_append (r, + upload_data, + *upload_data_size, + REQUEST_BUFFER_MAX)) + { + /* Request too long */ + *con_cls = NULL; + buffer_deinit (r); + GNUNET_free (r); + return (MHD_NO == + TMH_RESPONSE_reply_request_too_large (connection)) + ? GNUNET_SYSERR : GNUNET_NO; + } + /* everything OK, wait for more POST data */ + *upload_data_size = 0; + return GNUNET_YES; + } + + /* We have seen the whole request. */ + + *json = json_loadb (r->data, + r->fill, + 0, + NULL); + if (NULL == *json) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse JSON request body\n"); + return (MHD_YES == + TMH_RESPONSE_reply_invalid_json (connection)) + ? GNUNET_NO : GNUNET_SYSERR; + } + buffer_deinit (r); + GNUNET_free (r); + *con_cls = NULL; + + return GNUNET_YES; +} + + +/** + * Function called whenever we are done with a request + * to clean up our state. + * + * @param con_cls value as it was left by + * #TMH_PARSE_post_json(), to be cleaned up + */ +void +TMH_PARSE_post_cleanup_callback (void *con_cls) +{ + struct Buffer *r = con_cls; + + if (NULL != r) + { + buffer_deinit (r); + GNUNET_free (r); + } +} + + +/** + * Extract base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to store the result + * @param out_size expected size of data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size) +{ + const char *str; + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + param_name); + if (NULL == str) + { + return (MHD_NO == + TMH_RESPONSE_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out_data, + out_size)) + return (MHD_NO == + TMH_RESPONSE_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + return GNUNET_OK; +} + + +/** + * Extraxt variable-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing + * or the encoding is invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to allocate buffer and store the result + * @param[out] out_size set to the size of the buffer allocated in @a out_data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection, + const char *param_name, + void **out_data, + size_t *out_size) +{ + const char *str; + size_t slen; + size_t olen; + void *out; + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + param_name); + if (NULL == str) + { + return (MHD_NO == + TMH_RESPONSE_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + slen = strlen (str); + olen = (slen * 5) / 8; + out = GNUNET_malloc (olen); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out, + olen)) + { + GNUNET_free (out); + *out_size = 0; + return (MHD_NO == + TMH_RESPONSE_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + *out_data = out; + *out_size = olen; + return GNUNET_OK; +} + + +/** + * Navigate through a JSON tree. + * + * Sends an error response if navigation is impossible (i.e. + * the JSON object is invalid) + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`) + * @return + * #GNUNET_YES if navigation was successful + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error (no response was generated, + * connection must be closed) + */ +int +TMH_PARSE_navigate_json (struct MHD_Connection *connection, + const json_t *root, + ...) +{ + va_list argp; + int ret; + json_t *path; /* what's our current path from 'root'? */ + + path = json_array (); + va_start (argp, root); + ret = 2; /* just not any of the valid return values */ + while (2 == ret) + { + enum TMH_PARSE_JsonNavigationCommand command + = va_arg (argp, + enum TMH_PARSE_JsonNavigationCommand); + + switch (command) + { + case TMH_PARSE_JNC_FIELD: + { + const char *fname = va_arg(argp, const char *); + + json_array_append_new (path, + json_string (fname)); + root = json_object_get (root, + fname); + if (NULL == root) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s, s:O}", + "error", "missing field in JSON", + "field", fname, + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + } + break; + + case TMH_PARSE_JNC_INDEX: + { + int fnum = va_arg(argp, int); + + json_array_append_new (path, + json_integer (fnum)); + root = json_array_get (root, + fnum); + if (NULL == root) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "missing index in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + } + break; + + case TMH_PARSE_JNC_RET_DATA: + { + void *where = va_arg (argp, void *); + size_t len = va_arg (argp, size_t); + const char *str; + int res; + + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "string expected", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + res = GNUNET_STRINGS_string_to_data (str, strlen (str), + where, len); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed binary data in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; + } + break; + + case TMH_PARSE_JNC_RET_DATA_VAR: + { + void **where = va_arg (argp, void **); + size_t *len = va_arg (argp, size_t *); + const char *str; + int res; + + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_internal_error (connection, + "json_string_value() failed")) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *len = (strlen (str) * 5) / 8; + if (NULL != where) + { + *where = GNUNET_malloc (*len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + *where, + *len); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + GNUNET_free (*where); + *where = NULL; + *len = 0; + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed binary data in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + } + ret = GNUNET_OK; + } + break; + + case TMH_PARSE_JNC_RET_TYPED_JSON: + { + int typ = va_arg (argp, int); + const json_t **r_json = va_arg (argp, const json_t **); + + if ( (NULL == root) || + ( (-1 != typ) && + (json_typeof (root) != typ)) ) + { + GNUNET_break_op (0); + *r_json = NULL; + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:i, s:i, s:O}", + "error", "wrong JSON field type", + "type_expected", typ, + "type_actual", json_typeof (root), + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *r_json = root; + json_incref ((json_t *) root); + ret = GNUNET_OK; + } + break; + + case TMH_PARSE_JNC_RET_UINT64: + { + uint64_t *r_u64 = va_arg (argp, uint64_t *); + + if (json_typeof (root) != JSON_INTEGER) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s, s:i, s:O}", + "error", "wrong JSON field type", + "type_expected", "integer", + "type_actual", json_typeof (root), + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *r_u64 = (uint64_t) json_integer_value (root); + ret = GNUNET_OK; + } + break; + + case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: + { + struct TALER_DenominationPublicKey *where; + size_t len; + const char *str; + int res; + void *buf; + + where = va_arg (argp, + struct TALER_DenominationPublicKey *); + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "string expected", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + len = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + len); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + GNUNET_free (buf); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed binary data in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf, + len); + GNUNET_free (buf); + if (NULL == where->rsa_public_key) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed RSA public key in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; + break; + } + + case TMH_PARSE_JNC_RET_RSA_SIGNATURE: + { + struct TALER_DenominationSignature *where; + size_t len; + const char *str; + int res; + void *buf; + + where = va_arg (argp, + struct TALER_DenominationSignature *); + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "string expected", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + len = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + len); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + GNUNET_free (buf); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed binary data in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf, + len); + GNUNET_free (buf); + if (NULL == where->rsa_signature) + { + GNUNET_break_op (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "malformed RSA signature in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; + break; + } + + case TMH_PARSE_JNC_RET_AMOUNT: + { + struct TALER_Amount *where = va_arg (argp, void *); + + if (GNUNET_OK != + TALER_json_to_amount ((json_t *) root, + where)) + { + GNUNET_break_op (0); + ret = (MHD_YES != + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O}", + "error", "Bad format", + "path", path)) + ? GNUNET_SYSERR : GNUNET_NO; + break; + } + if (0 != strcmp (where->currency, + TMH_exchange_currency_string)) + { + GNUNET_break_op (0); + ret = (MHD_YES != + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:O, s:s}", + "error", "Currency not supported", + "path", path, + "currency", where->currency)) + ? GNUNET_SYSERR : GNUNET_NO; + memset (where, 0, sizeof (struct TALER_Amount)); + break; + } + ret = GNUNET_OK; + break; + } + + case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: + { + struct GNUNET_TIME_Absolute *where = va_arg (argp, void *); + + if (GNUNET_OK != + TALER_json_to_abs ((json_t *) root, + where)) + { + GNUNET_break_op (0); + ret = (MHD_YES != + TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s, s:O}", + "error", "Bad format", + "hint", "expected absolute time", + "path", path)) + ? GNUNET_SYSERR : GNUNET_NO; + break; + } + ret = GNUNET_OK; + break; + } + + default: + GNUNET_break (0); + ret = (MHD_YES == + TMH_RESPONSE_reply_internal_error (connection, + "unhandled value in switch")) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + } + va_end (argp); + json_decref (path); + return ret; +} + + +/** + * Parse JSON object into components based on the given field + * specification. + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param spec field specification for the parser + * @return + * #GNUNET_YES if navigation was successful (caller is responsible + * for freeing allocated variable-size data using + * #TMH_PARSE_release_data() when done) + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error + */ +int +TMH_PARSE_json_data (struct MHD_Connection *connection, + const json_t *root, + struct TMH_PARSE_FieldSpecification *spec) +{ + unsigned int i; + int ret; + + ret = GNUNET_YES; + for (i=0; NULL != spec[i].field_name; i++) + { + if (GNUNET_YES != ret) + break; + switch (spec[i].command) + { + case TMH_PARSE_JNC_FIELD: + GNUNET_break (0); + return GNUNET_SYSERR; + case TMH_PARSE_JNC_INDEX: + GNUNET_break (0); + return GNUNET_SYSERR; + case TMH_PARSE_JNC_RET_DATA: + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_DATA, + spec[i].destination, + spec[i].destination_size_in); + break; + case TMH_PARSE_JNC_RET_DATA_VAR: + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_DATA_VAR, + (void **) spec[i].destination, + spec[i].destination_size_out); + break; + case TMH_PARSE_JNC_RET_TYPED_JSON: + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_TYPED_JSON, + spec[i].type, + spec[i].destination); + break; + case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, + spec[i].destination); + break; + case TMH_PARSE_JNC_RET_RSA_SIGNATURE: + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_RSA_SIGNATURE, + spec[i].destination); + break; + case TMH_PARSE_JNC_RET_AMOUNT: + GNUNET_assert (sizeof (struct TALER_Amount) == + spec[i].destination_size_in); + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_AMOUNT, + spec[i].destination); + break; + case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: + GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) == + spec[i].destination_size_in); + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_TIME_ABSOLUTE, + spec[i].destination); + break; + case TMH_PARSE_JNC_RET_UINT64: + GNUNET_assert (sizeof (uint64_t) == + spec[i].destination_size_in); + ret = TMH_PARSE_navigate_json (connection, + root, + TMH_PARSE_JNC_FIELD, + spec[i].field_name, + TMH_PARSE_JNC_RET_UINT64, + spec[i].destination); + break; + } + } + if (GNUNET_YES != ret) + release_data (spec, + i - 1); + return ret; +} + + +/** + * Release all memory allocated for the variable-size fields in + * the parser specification. + * + * @param spec specification to free + */ +void +TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec) +{ + unsigned int i; + + for (i=0; NULL != spec[i].field_name; i++) ; + release_data (spec, i); +} + + +/** + * Generate line in parser specification for 64-bit integer + * given as an integer in JSON. + * + * @param field name of the field + * @param[out] u64 integer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_uint64 (const char *field, + uint64_t *u64) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 }; + return ret; +} + + +/** + * Generate line in parser specification for JSON object value. + * + * @param field name of the field + * @param[out] jsonp address of pointer to JSON to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_object (const char *field, + json_t **jsonp) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT }; + *jsonp = NULL; + return ret; +} + + +/** + * Generate line in parser specification for JSON array value. + * + * @param field name of the field + * @param[out] jsonp address of JSON pointer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_array (const char *field, + json_t **jsonp) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY }; + *jsonp = NULL; + return ret; +} + + +/** + * Generate line in parser specification for an absolute time. + * + * @param field name of the field + * @param[out] atime time to initialize + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_time_abs (const char *field, + struct GNUNET_TIME_Absolute *atime) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 }; + return ret; +} + + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param[out] pk key to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_denomination_public_key (const char *field, + struct TALER_DenominationPublicKey *pk) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 }; + pk->rsa_public_key = NULL; + return ret; +} + + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param sig the signature to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_denomination_signature (const char *field, + struct TALER_DenominationSignature *sig) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 }; + sig->rsa_signature = NULL; + return ret; +} + + +/** + * Generate line in parser specification for an amount. + * + * @param field name of the field + * @param amount a `struct TALER_Amount *` to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_amount (const char *field, + struct TALER_Amount *amount) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 }; + memset (amount, 0, sizeof (struct TALER_Amount)); + return ret; +} + + +/** + * Generate line in parser specification for variable-size value. + * + * @param field name of the field + * @param[out] ptr pointer to initialize + * @param[out] ptr_size size to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_variable (const char *field, + void **ptr, + size_t *ptr_size) +{ + struct TMH_PARSE_FieldSpecification ret = + { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 }; + *ptr = NULL; + return ret; +} + +/* end of taler-exchange-httpd_parsing.c */ diff --git a/src/exchange/taler-exchange-httpd_parsing.h b/src/exchange/taler-exchange-httpd_parsing.h new file mode 100644 index 000000000..a39235685 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_parsing.h @@ -0,0 +1,408 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_parsing.h + * @brief functions to parse incoming requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_PARSING_H +#define TALER_EXCHANGE_HTTPD_PARSING_H + +#include <microhttpd.h> +#include <jansson.h> +#include "taler_util.h" + + +/** + * Process a POST request containing a JSON object. This + * function realizes an MHD POST processor that will + * (incrementally) process JSON data uploaded to the HTTP + * server. It will store the required state in the + * "connection_cls", which must be cleaned up using + * #TMH_PARSE_post_cleanup_callback(). + * + * @param connection the MHD connection + * @param con_cls the closure (points to a `struct Buffer *`) + * @param upload_data the POST data + * @param upload_data_size number of bytes in @a upload_data + * @param json the JSON object for a completed request + * @return + * #GNUNET_YES if json object was parsed or at least + * may be parsed in the future (call again); + * `*json` will be NULL if we need to be called again, + * and non-NULL if we are done. + * #GNUNET_NO is request incomplete or invalid + * (error message was generated) + * #GNUNET_SYSERR on internal error + * (we could not even queue an error message, + * close HTTP session with MHD_NO) + */ +int +TMH_PARSE_post_json (struct MHD_Connection *connection, + void **con_cls, + const char *upload_data, + size_t *upload_data_size, + json_t **json); + + +/** + * Function called whenever we are done with a request + * to clean up our state. + * + * @param con_cls value as it was left by + * #TMH_PARSE_post_json(), to be cleaned up + */ +void +TMH_PARSE_post_cleanup_callback (void *con_cls); + + +/** + * Constants for JSON navigation description. + */ +enum TMH_PARSE_JsonNavigationCommand +{ + /** + * Access a field. + * Param: const char * + */ + TMH_PARSE_JNC_FIELD, + + /** + * Access an array index. + * Param: int + */ + TMH_PARSE_JNC_INDEX, + + /** + * Return base32crockford encoded data of + * constant size. + * Params: (void *, size_t) + */ + TMH_PARSE_JNC_RET_DATA, + + /** + * Return base32crockford encoded data of + * variable size. + * Params: (void **, size_t *) + */ + TMH_PARSE_JNC_RET_DATA_VAR, + + /** + * Return a json object, which must be + * of the given type (JSON_* type constants, + * or -1 for any type). + * Params: (int, json_t **) + */ + TMH_PARSE_JNC_RET_TYPED_JSON, + + /** + * Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was + * encoded as variable-size base32crockford encoded data. + */ + TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, + + /** + * Return a `struct GNUNET_CRYPTO_rsa_Signature` which was + * encoded as variable-size base32crockford encoded data. + */ + TMH_PARSE_JNC_RET_RSA_SIGNATURE, + + /** + * Return a `struct TALER_Amount` which was + * encoded within its own json object. + */ + TMH_PARSE_JNC_RET_AMOUNT, + + /** + * Return a `struct GNUNET_TIME_Absolute` which was + * encoded within its own json object. + * Param: struct GNUNET_TIME_Absolute * + */ + TMH_PARSE_JNC_RET_TIME_ABSOLUTE, + + /** + * Return a `uint64_t` which was + * encoded as a JSON integer. + * Param: uint64_t * + */ + TMH_PARSE_JNC_RET_UINT64 + +}; + + +/** + * Navigate through a JSON tree. + * + * Sends an error response if navigation is impossible (i.e. + * the JSON object is invalid) + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`) + * @return + * #GNUNET_YES if navigation was successful + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error + */ +int +TMH_PARSE_navigate_json (struct MHD_Connection *connection, + const json_t *root, + ...); + + +/** + * @brief Specification for how to parse a JSON field. + */ +struct TMH_PARSE_FieldSpecification +{ + /** + * Name of the field. NULL only to terminate array. + */ + const char *field_name; + + /** + * Where to store the result. Must have exactly + * @e destination_size bytes, except if @e destination_size is zero. + * NULL to skip assignment (but check presence of the value). + */ + void *destination; + + /** + * How big should the result be, 0 for variable size. In + * this case, @e destination must be a "void **", pointing + * to a location that is currently NULL and is to be allocated. + */ + size_t destination_size_in; + + /** + * @e destination_size_out will then be set to the size of the + * value that was stored in @e destination (useful for + * variable-size allocations). + */ + size_t *destination_size_out; + + /** + * Navigation command to use to extract the value. Note that + * #TMH_PARSE_JNC_RET_DATA or #TMH_PARSE_JNC_RET_DATA_VAR must be used for @e + * destination_size_in and @e destination_size_out to have a + * meaning. #TMH_PARSE_JNC_FIELD and #TMH_PARSE_JNC_INDEX must not be used here! + */ + enum TMH_PARSE_JsonNavigationCommand command; + + /** + * JSON type to use, only meaningful in connection with a @e command + * value of #TMH_PARSE_JNC_RET_TYPED_JSON. Typical values are + * #JSON_ARRAY and #JSON_OBJECT. + */ + int type; + +}; + + +/** + * Parse JSON object into components based on the given field + * specification. + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param spec field specification for the parser + * @return + * #GNUNET_YES if navigation was successful (caller is responsible + * for freeing allocated variable-size data using + * #TMH_PARSE_release_data() when done) + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error + */ +int +TMH_PARSE_json_data (struct MHD_Connection *connection, + const json_t *root, + struct TMH_PARSE_FieldSpecification *spec); + + +/** + * Release all memory allocated for the variable-size fields in + * the parser specification. + * + * @param spec specification to free + */ +void +TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec); + + +/** + * Generate line in parser specification for fixed-size value. + * + * @param field name of the field + * @param value where to store the value + */ +#define TMH_PARSE_member_fixed(field,value) { field, value, sizeof (*value), NULL, TMH_PARSE_JNC_RET_DATA, 0 } + + +/** + * Generate line in parser specification for variable-size value. + * + * @param field name of the field + * @param[out] ptr pointer to initialize + * @param[out] ptr_size size to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_variable (const char *field, + void **ptr, + size_t *ptr_size); + + +/** + * Generate line in parser specification for 64-bit integer + * given as an integer in JSON. + * + * @param field name of the field + * @param[out] u64 integer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_uint64 (const char *field, + uint64_t *u64); + + +/** + * Generate line in parser specification for JSON array value. + * + * @param field name of the field + * @param[out] jsonp address of JSON pointer to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_array (const char *field, + json_t **jsonp); + + +/** + * Generate line in parser specification for JSON object value. + * + * @param field name of the field + * @param[out] jsonp address of pointer to JSON to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_object (const char *field, + json_t **jsonp); + + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param[out] pk key to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_denomination_public_key (const char *field, + struct TALER_DenominationPublicKey *pk); + + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param sig the signature to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_denomination_signature (const char *field, + struct TALER_DenominationSignature *sig); + + +/** + * Generate line in parser specification for an amount. + * + * @param field name of the field + * @param[out] amount a `struct TALER_Amount *` to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_amount (const char *field, + struct TALER_Amount *amount); + + +/** + * Generate line in parser specification for an absolute time. + * + * @param field name of the field + * @param[out] atime time to initialize + * @return corresponding field spec + */ +struct TMH_PARSE_FieldSpecification +TMH_PARSE_member_time_abs (const char *field, + struct GNUNET_TIME_Absolute *atime); + + + +/** + * Generate line in parser specification indicating the end of the spec. + */ +#define TMH_PARSE_MEMBER_END { NULL, NULL, 0, NULL, TMH_PARSE_JNC_FIELD, 0 } + + +/** + * Extraxt fixed-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to store the result + * @param out_size expected size of @a out_data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size); + + +/** + * Extraxt variable-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing + * or the encoding is invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to allocate buffer and store the result + * @param[out] out_size set to the size of the buffer allocated in @a out_data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection, + const char *param_name, + void **out_data, + size_t *out_size); + + + + +#endif /* TALER_EXCHANGE_HTTPD_PARSING_H */ diff --git a/src/exchange/taler-exchange-httpd_refresh.c b/src/exchange/taler-exchange-httpd_refresh.c new file mode 100644 index 000000000..45bbf3d4d --- /dev/null +++ b/src/exchange/taler-exchange-httpd_refresh.c @@ -0,0 +1,911 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_refresh.c + * @brief Handle /refresh/ requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_mhd.h" +#include "taler-exchange-httpd_refresh.h" +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_keystate.h" + + +/** + * Handle a "/refresh/melt" request after the main JSON parsing has happened. + * We now need to validate the coins being melted and the session signature + * and then hand things of to execute the melt operation. + * + * @param connection the MHD connection to handle + * @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array + * @param denom_pubs array of @a num_new_denoms keys + * @param coin_count number of coins to be melted, size of y-dimension of @a commit_coin array + * @param coin_melt_details array with @a coin_count entries with melting details + * @param session_hash hash over the data that the client commits to + * @param commit_coin 2d array of coin commitments (what the exchange is to sign + * once the "/refres/reveal" of cut and choose is done) + * @param commit_link 2d array of coin link commitments (what the exchange is + * to return via "/refresh/link" to enable linkage in the + * future) + * @return MHD result code + */ +static int +handle_refresh_melt_binary (struct MHD_Connection *connection, + unsigned int num_new_denoms, + const struct TALER_DenominationPublicKey *denom_pubs, + unsigned int coin_count, + const struct TMH_DB_MeltDetails *coin_melt_details, + const struct GNUNET_HashCode *session_hash, + struct TALER_EXCHANGEDB_RefreshCommitCoin *const* commit_coin, + struct TALER_RefreshCommitLinkP *const* commit_link) +{ + unsigned int i; + struct TMH_KS_StateHandle *key_state; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk; + struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki; + struct TALER_Amount cost; + struct TALER_Amount total_cost; + struct TALER_Amount melt; + struct TALER_Amount value; + struct TALER_Amount fee_withdraw; + struct TALER_Amount fee_melt; + struct TALER_Amount total_melt; + + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (TMH_exchange_currency_string, + &total_cost)); + key_state = TMH_KS_acquire (); + for (i=0;i<num_new_denoms;i++) + { + dk = TMH_KS_denomination_key_lookup (key_state, + &denom_pubs[i], + TMH_KS_DKU_WITHDRAW); + if (NULL == dk) + { + GNUNET_break_op (0); + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_arg_invalid (connection, + "new_denoms"); + } + dki = &dk->issue; + TALER_amount_ntoh (&value, + &dki->properties.value); + TALER_amount_ntoh (&fee_withdraw, + &dki->properties.fee_withdraw); + if ( (GNUNET_OK != + TALER_amount_add (&cost, + &value, + &fee_withdraw)) || + (GNUNET_OK != + TALER_amount_add (&total_cost, + &cost, + &total_cost)) ) + { + GNUNET_break_op (0); + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_internal_error (connection, + "cost calculation failure"); + } + } + + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (TMH_exchange_currency_string, + &total_melt)); + for (i=0;i<coin_count;i++) + { + /* calculate contribution of the i-th melt by subtracting + the fee; add the rest to the total_melt value */ + dk = TMH_KS_denomination_key_lookup (key_state, + &coin_melt_details[i].coin_info.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dk) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_arg_invalid (connection, + "denom_pub"); + } + dki = &dk->issue; + TALER_amount_ntoh (&fee_melt, + &dki->properties.fee_refresh); + if (GNUNET_OK != + TALER_amount_subtract (&melt, + &coin_melt_details->melt_amount_with_fee, + &fee_melt)) + { + GNUNET_break_op (0); + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_external_error (connection, + "Melt contribution below melting fee"); + } + if (GNUNET_OK != + TALER_amount_add (&total_melt, + &melt, + &total_melt)) + { + GNUNET_break_op (0); + TMH_KS_release (key_state); + return TMH_RESPONSE_reply_internal_error (connection, + "balance calculation failure"); + } + } + TMH_KS_release (key_state); + if (0 != + TALER_amount_cmp (&total_cost, + &total_melt)) + { + GNUNET_break_op (0); + /* We require total value of coins being melted and + total value of coins being generated to match! */ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", "value mismatch"); + } + return TMH_DB_execute_refresh_melt (connection, + session_hash, + num_new_denoms, + denom_pubs, + coin_count, + coin_melt_details, + commit_coin, + commit_link); +} + + +/** + * Extract public coin information from a JSON object. + * + * @param connection the connection to send error responses to + * @param coin_info the JSON object to extract the coin info from + * @param[out] r_melt_detail set to details about the coin's melting permission (if valid) + * @return #GNUNET_YES if coin public info in JSON was valid + * #GNUNET_NO JSON was invalid, response was generated + * #GNUNET_SYSERR on internal error + */ +static int +get_coin_public_info (struct MHD_Connection *connection, + json_t *coin_info, + struct TMH_DB_MeltDetails *r_melt_detail) +{ + int ret; + struct TALER_CoinSpendSignatureP melt_sig; + struct TALER_DenominationSignature sig; + struct TALER_DenominationPublicKey pk; + struct TALER_Amount amount; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub), + TMH_PARSE_member_denomination_signature ("denom_sig", &sig), + TMH_PARSE_member_denomination_public_key ("denom_pub", &pk), + TMH_PARSE_member_fixed ("confirm_sig", &melt_sig), + TMH_PARSE_member_amount ("value_with_fee", &amount), + TMH_PARSE_MEMBER_END + }; + + ret = TMH_PARSE_json_data (connection, + coin_info, + spec); + if (GNUNET_OK != ret) + { + GNUNET_break_op (0); + return ret; + } + /* check exchange signature on the coin */ + r_melt_detail->coin_info.denom_sig = sig; + r_melt_detail->coin_info.denom_pub = pk; + if (GNUNET_OK != + TALER_test_coin_valid (&r_melt_detail->coin_info)) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + r_melt_detail->coin_info.denom_sig.rsa_signature = NULL; + r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL; + return (MHD_YES == + TMH_RESPONSE_reply_signature_invalid (connection, + "denom_sig")) + ? GNUNET_NO : GNUNET_SYSERR; + } + r_melt_detail->melt_sig = melt_sig; + r_melt_detail->melt_amount_with_fee = amount; + return GNUNET_OK; +} + + +/** + * Verify that the signature shows that this coin is to be melted into + * the given @a session_hash melting session, and that this is a valid + * coin (we know the denomination key and the signature on it is + * valid). Essentially, this does all of the per-coin checks that can + * be done before the transaction starts. + * + * @param connection the connection to send error responses to + * @param session_hash hash over refresh session the coin is melted into + * @param[in,out] melt_detail details about the coin's melting permission, + * the `melt_fee` is updated + * @return #GNUNET_YES if coin public info in JSON was valid + * #GNUNET_NO JSON was invalid, response was generated + * #GNUNET_SYSERR on internal error + */ +static int +verify_coin_public_info (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + struct TMH_DB_MeltDetails *melt_detail) +{ + struct TALER_RefreshMeltCoinAffirmationPS body; + struct TMH_KS_StateHandle *key_state; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TALER_Amount fee_refresh; + + key_state = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (key_state, + &melt_detail->coin_info.denom_pub, + TMH_KS_DKU_DEPOSIT); + if (NULL == dki) + { + TMH_KS_release (key_state); + TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); + return TMH_RESPONSE_reply_arg_unknown (connection, + "denom_pub"); + } + TALER_amount_ntoh (&fee_refresh, + &dki->issue.properties.fee_refresh); + melt_detail->melt_fee = fee_refresh; + body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); + body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); + body.session_hash = *session_hash; + TALER_amount_hton (&body.amount_with_fee, + &melt_detail->melt_amount_with_fee); + TALER_amount_hton (&body.melt_fee, + &fee_refresh); + body.coin_pub = melt_detail->coin_info.coin_pub; + if (TALER_amount_cmp (&fee_refresh, + &melt_detail->melt_amount_with_fee) > 0) + { + GNUNET_break_op (0); + TMH_KS_release (key_state); + return (MHD_YES == + TMH_RESPONSE_reply_external_error (connection, + "melt amount smaller than melting fee")) + ? GNUNET_NO : GNUNET_SYSERR; + } + + TMH_KS_release (key_state); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, + &body.purpose, + &melt_detail->melt_sig.eddsa_signature, + &melt_detail->coin_info.coin_pub.eddsa_pub)) + { + GNUNET_break_op (0); + if (MHD_YES != + TMH_RESPONSE_reply_signature_invalid (connection, + "confirm_sig")) + return GNUNET_SYSERR; + return GNUNET_NO; + } + return GNUNET_OK; +} + + +/** + * Release memory from the @a commit_coin array. + * + * @param commit_coin array to release + * @param kappa size of 1st dimension + * @param num_new_coins size of 2nd dimension + */ +static void +free_commit_coins (struct TALER_EXCHANGEDB_RefreshCommitCoin **commit_coin, + unsigned int kappa, + unsigned int num_new_coins) +{ + unsigned int i; + unsigned int j; + + for (i=0;i<kappa;i++) + { + if (NULL == commit_coin[i]) + break; + for (j=0;j<num_new_coins;j++) + { + GNUNET_free_non_null (commit_coin[i][j].coin_ev); + GNUNET_free_non_null (commit_coin[i][j].refresh_link); + } + GNUNET_free (commit_coin[i]); + } +} + + +/** + * Release memory from the @a commit_link array. + * + * @param commit_link array to release + * @param kappa size of 1st dimension + * @param num_old_coins size of 2nd dimension + */ +static void +free_commit_links (struct TALER_RefreshCommitLinkP **commit_link, + unsigned int kappa, + unsigned int num_old_coins) +{ + unsigned int i; + + for (i=0;i<kappa;i++) + { + if (NULL == commit_link[i]) + break; + GNUNET_free (commit_link[i]); + } +} + + +/** + * Handle a "/refresh/melt" request after the first parsing has happened. + * We now need to validate the coins being melted and the session signature + * and then hand things of to execute the melt operation. This function + * parses the JSON arrays and then passes processing on to + * #handle_refresh_melt_binary(). + * + * @param connection the MHD connection to handle + * @param new_denoms array of denomination keys + * @param melt_coins array of coins to melt + * @param num_oldcoins number of coins that are being melted + * @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins transfer keys + * @param secret_encs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins secrets + * @param num_newcoins number of coins that the refresh will generate + * @param coin_evs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins envelopes to sign + * @param link_encs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins encrypted links + * @return MHD result code + */ +static int +handle_refresh_melt_json (struct MHD_Connection *connection, + const json_t *new_denoms, + const json_t *melt_coins, + unsigned int num_oldcoins, + const json_t *transfer_pubs, + const json_t *secret_encs, + unsigned int num_newcoins, + const json_t *coin_evs, + const json_t *link_encs) +{ + int res; + unsigned int i; + unsigned int j; + struct TALER_DenominationPublicKey *denom_pubs; + unsigned int num_new_denoms; + struct TMH_DB_MeltDetails *coin_melt_details; + unsigned int coin_count; + struct GNUNET_HashCode session_hash; + struct GNUNET_HashContext *hash_context; + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA]; + struct TALER_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA]; + + /* For the signature check, we hash most of the inputs together + (except for the signatures on the coins). */ + hash_context = GNUNET_CRYPTO_hash_context_start (); + num_new_denoms = json_array_size (new_denoms); + denom_pubs = GNUNET_malloc (num_new_denoms * + sizeof (struct TALER_DenominationPublicKey)); + for (i=0;i<num_new_denoms;i++) + { + char *buf; + size_t buf_size; + + res = TMH_PARSE_navigate_json (connection, + new_denoms, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, + &denom_pubs[i].rsa_public_key); + if (GNUNET_OK != res) + { + res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; + goto cleanup_denoms; + } + buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key, + &buf); + GNUNET_CRYPTO_hash_context_read (hash_context, + buf, + buf_size); + GNUNET_free (buf); + } + + coin_count = json_array_size (melt_coins); + coin_melt_details = GNUNET_new_array (coin_count, + struct TMH_DB_MeltDetails); + for (i=0;i<coin_count;i++) + { + /* decode JSON data on coin to melt */ + struct TALER_AmountNBO melt_amount; + + res = get_coin_public_info (connection, + json_array_get (melt_coins, i), + &coin_melt_details[i]); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; + goto cleanup_melt_details; + } + /* Check that the client does not try to melt the same coin twice + into the same session! */ + for (j=0;j<i;j++) + { + if (0 == memcmp (&coin_melt_details[i].coin_info.coin_pub, + &coin_melt_details[j].coin_info.coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP))) + { + GNUNET_break_op (0); + res = TMH_RESPONSE_reply_external_error (connection, + "melting same coin twice in same session is not allowed"); + goto cleanup_melt_details; + } + } + TALER_amount_hton (&melt_amount, + &coin_melt_details[i].melt_amount_with_fee); + GNUNET_CRYPTO_hash_context_read (hash_context, + &coin_melt_details[i].coin_info.coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)); + GNUNET_CRYPTO_hash_context_read (hash_context, + &melt_amount, + sizeof (struct TALER_AmountNBO)); + } + + /* parse JSON arrays into 2d binary arrays and hash everything + together for the signature check */ + memset (commit_coin, 0, sizeof (commit_coin)); + memset (commit_link, 0, sizeof (commit_link)); + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + commit_coin[i] = GNUNET_malloc (num_newcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin)); + for (j = 0; j < num_newcoins; j++) + { + char *link_enc; + size_t link_enc_size; + struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &commit_coin[i][j]; + + res = TMH_PARSE_navigate_json (connection, + coin_evs, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_INDEX, (int) j, + TMH_PARSE_JNC_RET_DATA_VAR, + &rcc->coin_ev, + &rcc->coin_ev_size); + + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + goto cleanup; + } + + GNUNET_CRYPTO_hash_context_read (hash_context, + rcc->coin_ev, + rcc->coin_ev_size); + res = TMH_PARSE_navigate_json (connection, + link_encs, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_INDEX, (int) j, + TMH_PARSE_JNC_RET_DATA_VAR, + &link_enc, + &link_enc_size); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + goto cleanup; + } + rcc->refresh_link + = TALER_refresh_link_encrypted_decode (link_enc, + link_enc_size); + GNUNET_CRYPTO_hash_context_read (hash_context, + link_enc, + link_enc_size); + GNUNET_free (link_enc); + } + } + + for (i = 0; i < TALER_CNC_KAPPA; i++) + { + commit_link[i] = GNUNET_malloc (num_oldcoins * + sizeof (struct TALER_RefreshCommitLinkP)); + for (j = 0; j < num_oldcoins; j++) + { + struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j]; + + res = TMH_PARSE_navigate_json (connection, + transfer_pubs, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_INDEX, (int) j, + TMH_PARSE_JNC_RET_DATA, + &rcl->transfer_pub, + sizeof (struct TALER_TransferPublicKeyP)); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + goto cleanup; + } + res = TMH_PARSE_navigate_json (connection, + secret_encs, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_INDEX, (int) j, + TMH_PARSE_JNC_RET_DATA, + &rcl->shared_secret_enc, + sizeof (struct TALER_EncryptedLinkSecretP)); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + goto cleanup; + } + GNUNET_CRYPTO_hash_context_read (hash_context, + rcl, + sizeof (struct TALER_RefreshCommitLinkP)); + } + } + GNUNET_CRYPTO_hash_context_finish (hash_context, + &session_hash); + hash_context = NULL; + for (i=0;i<coin_count;i++) + { + /* verify signatures on coins to melt */ + res = verify_coin_public_info (connection, + &session_hash, + &coin_melt_details[i]); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; + goto cleanup; + } + } + + /* execute commit */ + res = handle_refresh_melt_binary (connection, + num_new_denoms, + denom_pubs, + coin_count, + coin_melt_details, + &session_hash, + commit_coin, + commit_link); + cleanup: + free_commit_coins (commit_coin, + TALER_CNC_KAPPA, + num_newcoins); + free_commit_links (commit_link, + TALER_CNC_KAPPA, + num_oldcoins); + cleanup_melt_details: + for (j=0;j<coin_count;j++) + { + if (NULL != coin_melt_details[j].coin_info.denom_pub.rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key); + if (NULL != coin_melt_details[j].coin_info.denom_sig.rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature); + } + GNUNET_free (coin_melt_details); + cleanup_denoms: + for (j=0;j<num_new_denoms;j++) + if (NULL != denom_pubs[j].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); + GNUNET_free (denom_pubs); + if (NULL != hash_context) + GNUNET_CRYPTO_hash_context_abort (hash_context); + return res; +} + + +/** + * Handle a "/refresh/melt" request. Parses the request into the JSON + * components and then hands things of to #handle_refresh_melt_json() + * to validate the melted coins, the signature and execute the melt + * using TMH_DB_execute_refresh_melt(). + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *root; + json_t *new_denoms; + json_t *melt_coins; + json_t *coin_evs; + json_t *link_encs; + json_t *transfer_pubs; + json_t *secret_encs; + unsigned int num_oldcoins; + unsigned int num_newcoins; + json_t *coin_detail; + int res; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_array ("new_denoms", &new_denoms), + TMH_PARSE_member_array ("melt_coins", &melt_coins), + TMH_PARSE_member_array ("coin_evs", &coin_evs), + TMH_PARSE_member_array ("link_encs", &link_encs), + TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs), + TMH_PARSE_member_array ("secret_encs", &secret_encs), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == root) ) + return MHD_YES; + + res = TMH_PARSE_json_data (connection, + root, + spec); + json_decref (root); + if (GNUNET_OK != res) + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + + /* Determine dimensionality of the request (kappa, #old and #new coins) */ + if (TALER_CNC_KAPPA != json_array_size (coin_evs)) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_invalid (connection, + "coin_evs"); + } + if (TALER_CNC_KAPPA != json_array_size (transfer_pubs)) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_arg_invalid (connection, + "transfer_pubs"); + } + res = TMH_PARSE_navigate_json (connection, + coin_evs, + TMH_PARSE_JNC_INDEX, (int) 0, + TMH_PARSE_JNC_RET_TYPED_JSON, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + num_newcoins = json_array_size (coin_detail); + json_decref (coin_detail); + res = TMH_PARSE_navigate_json (connection, + transfer_pubs, + TMH_PARSE_JNC_INDEX, (int) 0, + TMH_PARSE_JNC_RET_TYPED_JSON, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + TMH_PARSE_release_data (spec); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + num_oldcoins = json_array_size (coin_detail); + json_decref (coin_detail); + res = handle_refresh_melt_json (connection, + new_denoms, + melt_coins, + num_oldcoins, + transfer_pubs, + secret_encs, + num_newcoins, + coin_evs, + link_encs); + TMH_PARSE_release_data (spec); + return res; +} + + +/** + * Handle a "/refresh/reveal" request. Parses the given JSON + * transfer private keys and if successful, passes everything to + * #TMH_DB_execute_refresh_reveal() which will verify that the + * revealed information is valid then returns the signed refreshed + * coins. + * + * @param connection the MHD connection to handle + * @param session_hash hash identifying the melting session + * @param num_oldcoins length of the 2nd dimension of @a transfer_privs array + * @param tp_json private transfer keys in JSON format + * @return MHD result code + */ +static int +handle_refresh_reveal_json (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + unsigned int num_oldcoins, + const json_t *tp_json) +{ + struct TALER_TransferPrivateKeyP *transfer_privs[TALER_CNC_KAPPA - 1]; + unsigned int i; + unsigned int j; + int res; + + for (i = 0; i < TALER_CNC_KAPPA - 1; i++) + transfer_privs[i] = GNUNET_malloc (num_oldcoins * + sizeof (struct TALER_TransferPrivateKeyP)); + res = GNUNET_OK; + for (i = 0; i < TALER_CNC_KAPPA - 1; i++) + { + if (GNUNET_OK != res) + break; + for (j = 0; j < num_oldcoins; j++) + { + if (GNUNET_OK != res) + break; + res = TMH_PARSE_navigate_json (connection, + tp_json, + TMH_PARSE_JNC_INDEX, (int) i, + TMH_PARSE_JNC_INDEX, (int) j, + TMH_PARSE_JNC_RET_DATA, + &transfer_privs[i][j], + sizeof (struct TALER_TransferPrivateKeyP)); + GNUNET_break_op (GNUNET_OK == res); + } + } + if (GNUNET_OK != res) + res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + else + res = TMH_DB_execute_refresh_reveal (connection, + session_hash, + num_oldcoins, + transfer_privs); + for (i = 0; i < TALER_CNC_KAPPA - 1; i++) + GNUNET_free (transfer_privs[i]); + return res; +} + + +/** + * Handle a "/refresh/reveal" request. This time, the client reveals + * the private transfer keys except for the cut-and-choose value + * returned from "/refresh/melt". This function parses the revealed + * keys and secrets and ultimately passes everything to + * #TMH_DB_execute_refresh_reveal() which will verify that the + * revealed information is valid then returns the signed refreshed + * coins. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct GNUNET_HashCode session_hash; + int res; + unsigned int num_oldcoins; + json_t *reveal_detail; + json_t *root; + json_t *transfer_privs; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("session_hash", &session_hash), + TMH_PARSE_member_array ("transfer_privs", &transfer_privs), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == root) ) + return MHD_YES; + + res = TMH_PARSE_json_data (connection, + root, + spec); + json_decref (root); + if (GNUNET_OK != res) + { + GNUNET_break_op (0); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + /* Determine dimensionality of the request (kappa and #old coins) */ + /* Note we do +1 as 1 row (cut-and-choose!) is missing! */ + if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1) + { + TMH_PARSE_release_data (spec); + GNUNET_break_op (0); + return TMH_RESPONSE_reply_arg_invalid (connection, + "transfer_privs"); + } + res = TMH_PARSE_navigate_json (connection, + transfer_privs, + TMH_PARSE_JNC_INDEX, 0, + TMH_PARSE_JNC_RET_TYPED_JSON, + JSON_ARRAY, + &reveal_detail); + if (GNUNET_OK != res) + { + TMH_PARSE_release_data (spec); + GNUNET_break_op (0); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + num_oldcoins = json_array_size (reveal_detail); + json_decref (reveal_detail); + res = handle_refresh_reveal_json (connection, + &session_hash, + num_oldcoins, + transfer_privs); + TMH_PARSE_release_data (spec); + return res; +} + + +/** + * Handle a "/refresh/link" request. Note that for "/refresh/link" + * we do use a simple HTTP GET, and a HTTP POST! + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TALER_CoinSpendPublicKeyP coin_pub; + int res; + + res = TMH_PARSE_mhd_request_arg_data (connection, + "coin_pub", + &coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)); + if (GNUNET_SYSERR == res) + return MHD_NO; + if (GNUNET_OK != res) + return MHD_YES; + return TMH_DB_execute_refresh_link (connection, + &coin_pub); +} + + +/* end of taler-exchange-httpd_refresh.c */ diff --git a/src/exchange/taler-exchange-httpd_refresh.h b/src/exchange/taler-exchange-httpd_refresh.h new file mode 100644 index 000000000..aae9c4c6c --- /dev/null +++ b/src/exchange/taler-exchange-httpd_refresh.h @@ -0,0 +1,94 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_refresh.h + * @brief Handle /refresh/ requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_REFRESH_H +#define TALER_EXCHANGE_HTTPD_REFRESH_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/refresh/melt" request. Parses the request into the JSON + * components and then hands things of to #handle_refresh_melt_json() + * to validate the melted coins, the signature and execute the melt + * using TMH_DB_execute_refresh_melt(). + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/refresh/reveal" request. This time, the client reveals + * the private transfer keys except for the cut-and-choose value + * returned from "/refresh/commit". This function parses the revealed + * keys and secrets and ultimately passes everything to + * #TMH_DB_execute_refresh_reveal() which will verify that the + * revealed information is valid then returns the signed refreshed + * coins. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/refresh/link" request + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_reserve.c b/src/exchange/taler-exchange-httpd_reserve.c new file mode 100644 index 000000000..45f073107 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_reserve.c @@ -0,0 +1,186 @@ +/* + This file is part of TALER + Copyright (C) 2014,2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_reserve.c + * @brief Handle /reserve/ requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include "taler-exchange-httpd_reserve.h" +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_keystate.h" + + +/** + * Handle a "/reserve/status" request. Parses the + * given "reserve_pub" argument (which should contain the + * EdDSA public key of a reserve) and then respond with the + * status of the reserve. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TALER_ReservePublicKeyP reserve_pub; + int res; + + res = TMH_PARSE_mhd_request_arg_data (connection, + "reserve_pub", + &reserve_pub, + sizeof (struct TALER_ReservePublicKeyP)); + if (GNUNET_SYSERR == res) + return MHD_NO; /* internal error */ + if (GNUNET_NO == res) + return MHD_YES; /* parse error */ + return TMH_DB_execute_reserve_status (connection, + &reserve_pub); +} + + +/** + * Handle a "/reserve/withdraw" request. Parses the "reserve_pub" + * EdDSA key of the reserve and the requested "denom_pub" which + * specifies the key/value of the coin to be withdrawn, and checks + * that the signature "reserve_sig" makes this a valid withdrawl + * request from the specified reserve. If so, the envelope + * with the blinded coin "coin_ev" is passed down to execute the + * withdrawl operation. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *root; + struct TALER_WithdrawRequestPS wsrd; + int res; + struct TALER_DenominationPublicKey denomination_pub; + char *blinded_msg; + size_t blinded_msg_len; + struct TALER_Amount amount; + struct TALER_Amount amount_with_fee; + struct TALER_Amount fee_withdraw; + struct TALER_ReserveSignatureP signature; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TMH_KS_StateHandle *ks; + + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_variable ("coin_ev", + (void **) &blinded_msg, + &blinded_msg_len), + TMH_PARSE_member_fixed ("reserve_pub", + &wsrd.reserve_pub), + TMH_PARSE_member_fixed ("reserve_sig", + &signature), + TMH_PARSE_member_denomination_public_key ("denom_pub", + &denomination_pub), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == root) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + root, + spec); + json_decref (root); + if (GNUNET_OK != res) + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + ks = TMH_KS_acquire (); + dki = TMH_KS_denomination_key_lookup (ks, + &denomination_pub, + TMH_KS_DKU_WITHDRAW); + if (NULL == dki) + { + TMH_PARSE_release_data (spec); + TMH_KS_release (ks); + return TMH_RESPONSE_reply_arg_unknown (connection, + "denom_pub"); + } + TALER_amount_ntoh (&amount, + &dki->issue.properties.value); + TALER_amount_ntoh (&fee_withdraw, + &dki->issue.properties.fee_withdraw); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&amount_with_fee, + &amount, + &fee_withdraw)); + TALER_amount_hton (&wsrd.amount_with_fee, + &amount_with_fee); + TALER_amount_hton (&wsrd.withdraw_fee, + &fee_withdraw); + TMH_KS_release (ks); + /* verify signature! */ + wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); + wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); + + GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key, + &wsrd.h_denomination_pub); + GNUNET_CRYPTO_hash (blinded_msg, + blinded_msg_len, + &wsrd.h_coin_envelope); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, + &wsrd.purpose, + &signature.eddsa_signature, + &wsrd.reserve_pub.eddsa_pub)) + { + TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n"); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_signature_invalid (connection, + "reserve_sig"); + } + res = TMH_DB_execute_reserve_withdraw (connection, + &wsrd.reserve_pub, + &denomination_pub, + blinded_msg, + blinded_msg_len, + &signature); + TMH_PARSE_release_data (spec); + return res; +} + +/* end of taler-exchange-httpd_reserve.c */ diff --git a/src/exchange/taler-exchange-httpd_reserve.h b/src/exchange/taler-exchange-httpd_reserve.h new file mode 100644 index 000000000..9a4960066 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_reserve.h @@ -0,0 +1,73 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_reserve.h + * @brief Handle /reserve/ requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_RESERVE_H +#define TALER_EXCHANGE_HTTPD_RESERVE_H + +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + +/** + * Handle a "/reserve/status" request. Parses the + * given "reserve_pub" argument (which should contain the + * EdDSA public key of a reserve) and then respond with the + * status of the reserve. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/reserve/withdraw" request. Parses the "reserve_pub" + * EdDSA key of the reserve and the requested "denom_pub" which + * specifies the key/value of the coin to be withdrawn, and checks + * that the signature "reserve_sig" makes this a valid withdrawl + * request from the specified reserve. If so, the envelope + * with the blinded coin "coin_ev" is passed down to execute the + * withdrawl operation. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + +#endif diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c new file mode 100644 index 000000000..d6cf81bb7 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -0,0 +1,1177 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_responses.c + * @brief API for generating the various replies of the exchange; these + * functions are called TMH_RESPONSE_reply_ and they generate + * and queue MHD response objects for a given connection. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-exchange-httpd_responses.h" +#include "taler_util.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler-exchange-httpd_keystate.h" + + +/** + * Add headers we want to return in every response. + * Useful for testing, like if we want to always close + * connections. + * + * @param response response to modify + */ +void +TMH_RESPONSE_add_global_headers (struct MHD_Response *response) +{ + if (TMH_exchange_connection_close) + (void) MHD_add_response_header (response, + MHD_HTTP_HEADER_CONNECTION, + "close"); +} + + +/** + * Send JSON object as response. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TMH_RESPONSE_reply_json (struct MHD_Connection *connection, + const json_t *json, + unsigned int response_code) +{ + struct MHD_Response *resp; + char *json_str; + int ret; + + json_str = json_dumps (json, JSON_INDENT(2)); + GNUNET_assert (NULL != json_str); + resp = MHD_create_response_from_buffer (strlen (json_str), json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + { + free (json_str); + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (resp); + (void) MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json"); + ret = MHD_queue_response (connection, + response_code, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** + * Function to call to handle the request by building a JSON + * reply from a format string and varargs. + * + * @param connection the MHD connection to handle + * @param response_code HTTP response code to use + * @param fmt format string for pack + * @param ... varargs + * @return MHD result code + */ +int +TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...) +{ + json_t *json; + va_list argp; + int ret; + json_error_t jerror; + + va_start (argp, fmt); + json = json_vpack_ex (&jerror, 0, fmt, argp); + va_end (argp); + if (NULL == json) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to pack JSON with format `%s': %s\n", + fmt, + jerror.text); + GNUNET_break (0); + return MHD_NO; + } + ret = TMH_RESPONSE_reply_json (connection, + json, + response_code); + json_decref (json); + return ret; +} + + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s}", + "error", "invalid parameter", + "parameter", param_name); +} + + +/** + * Send a response indicating an argument refering to a + * resource unknown to the exchange (i.e. unknown reserve or + * denomination key). + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s, s:s}", + "error", "unknown entity referenced", + "parameter", param_name); +} + + +/** + * Send a response indicating an invalid signature. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s, s:s}", + "error", "invalid signature", + "parameter", param_name); +} + + +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{ s:s, s:s}", + "error", "missing parameter", + "parameter", param_name); +} + + +/** + * Send a response indicating permission denied. + * + * @param connection the MHD connection to use + * @param hint hint about why access was denied + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, + const char *hint) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s, s:s}", + "error", "permission denied", + "hint", hint); +} + + +/** + * Send a response indicating an internal error. + * + * @param connection the MHD connection to use + * @param hint hint about the internal error's nature + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + const char *hint) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + "{s:s, s:s}", + "error", "internal error", + "hint", hint); +} + + +/** + * Send a response indicating an external error. + * + * @param connection the MHD connection to use + * @param hint hint about the error's nature + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + const char *hint) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s}", + "error", "client error", + "hint", hint); +} + + +/** + * Send a response indicating an error committing a + * transaction (concurrent interference). + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", "commit failure"); +} + + +/** + * Send a response indicating a failure to talk to the Exchange's + * database. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection) +{ + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to connect to database"); +} + + +/** + * Send a response indicating that the request was too big. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection) +{ + struct MHD_Response *resp; + int ret; + + resp = MHD_create_response_from_buffer (0, + NULL, + MHD_RESPMEM_PERSISTENT); + if (NULL == resp) + return MHD_NO; + TMH_RESPONSE_add_global_headers (resp); + ret = MHD_queue_response (connection, + MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** + * Send a response indicating that the JSON was malformed. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", + "invalid json"); +} + + +/** + * Send confirmation of deposit success to client. This function + * will create a signed message affirming the given information + * and return it to the client. By this, the exchange affirms that + * the coin had sufficient (residual) value for the specified + * transaction and that it will execute the requested deposit + * operation with the given wiring details. + * + * @param connection connection to the client + * @param coin_pub public key of the coin + * @param h_wire hash of wire details + * @param h_contract hash of contract details + * @param transaction_id transaction ID + * @param timestamp client's timestamp + * @param refund_deadline until when this deposit be refunded + * @param merchant merchant public key + * @param amount_without_fee fraction of coin value to deposit, without the fee + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_MerchantPublicKeyP *merchant, + const struct TALER_Amount *amount_without_fee) +{ + struct TALER_DepositConfirmationPS dc; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + + dc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT); + dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); + dc.h_contract = *h_contract; + dc.h_wire = *h_wire; + dc.transaction_id = GNUNET_htonll (transaction_id); + dc.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + TALER_amount_hton (&dc.amount_without_fee, + amount_without_fee); + dc.coin_pub = *coin_pub; + dc.merchant = *merchant; + TMH_KS_sign (&dc.purpose, + &pub, + &sig); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s, s:o, s:o}", + "status", "DEPOSIT_OK", + "sig", TALER_json_from_data (&sig, + sizeof (sig)), + "pub", TALER_json_from_data (&pub, + sizeof (pub))); +} + + +/** + * Compile the transaction history of a coin into a JSON object. + * + * @param tl transaction history to JSON-ify + * @return json representation of the @a rh + */ +static json_t * +compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl) +{ + json_t *details; + const char *type; + struct TALER_Amount value; + json_t *history; + const struct TALER_CoinSpendSignatureP *sig; + const struct TALER_EXCHANGEDB_TransactionList *pos; + + history = json_array (); + for (pos = tl; NULL != pos; pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_TT_DEPOSIT: + { + struct TALER_DepositRequestPS dr; + const struct TALER_EXCHANGEDB_Deposit *deposit = pos->details.deposit; + + type = "DEPOSIT"; + value = deposit->amount_with_fee; + dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); + dr.h_contract = deposit->h_contract; + dr.h_wire = deposit->h_wire; + dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); + dr.transaction_id = GNUNET_htonll (deposit->transaction_id); + TALER_amount_hton (&dr.amount_with_fee, + &deposit->amount_with_fee); + TALER_amount_hton (&dr.deposit_fee, + &deposit->deposit_fee); + dr.merchant = deposit->merchant_pub; + dr.coin_pub = deposit->coin.coin_pub; + sig = &deposit->csig; + /* internal sanity check before we hand out a bogus sig... */ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, + &dr.purpose, + &sig->eddsa_signature, + &deposit->coin.coin_pub.eddsa_pub)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + + details = TALER_json_from_data (&dr.purpose, + sizeof (struct TALER_DepositRequestPS)); + break; + } + case TALER_EXCHANGEDB_TT_REFRESH_MELT: + { + struct TALER_RefreshMeltCoinAffirmationPS ms; + const struct TALER_EXCHANGEDB_RefreshMelt *melt = pos->details.melt; + + type = "MELT"; + value = melt->amount_with_fee; + ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); + ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); + ms.session_hash = melt->session_hash; + TALER_amount_hton (&ms.amount_with_fee, + &melt->amount_with_fee); + TALER_amount_hton (&ms.melt_fee, + &melt->melt_fee); + ms.coin_pub = melt->coin.coin_pub; + sig = &melt->coin_sig; + /* internal sanity check before we hand out a bogus sig... */ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, + &ms.purpose, + &sig->eddsa_signature, + &melt->coin.coin_pub.eddsa_pub)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + + details = TALER_json_from_data (&ms.purpose, + sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); + } + break; + default: + GNUNET_assert (0); + } + json_array_append_new (history, + json_pack ("{s:s, s:o, s:o, s:o}", + "type", type, + "amount", TALER_json_from_amount (&value), + "signature", TALER_json_from_data (sig, + sizeof (struct TALER_CoinSpendSignatureP)), + "details", details)); + } + return history; +} + + +/** + * Send proof that a /deposit request is invalid to client. This + * function will create a message with all of the operations affecting + * the coin that demonstrate that the coin has insufficient value. + * + * @param connection connection to the client + * @param tl transaction list to use to build reply + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_TransactionList *tl) +{ + json_t *history; + + history = compile_transaction_history (tl); + if (NULL == history) + return TMH_RESPONSE_reply_internal_db_error (connection); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s, s:o}", + "error", "insufficient funds", + "history", history); +} + + +/** + * Compile the history of a reserve into a JSON object + * and calculate the total balance. + * + * @param rh reserve history to JSON-ify + * @param[out] balance set to current reserve balance + * @return json representation of the @a rh, NULL on error + */ +static json_t * +compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh, + struct TALER_Amount *balance) +{ + struct TALER_Amount deposit_total; + struct TALER_Amount withdraw_total; + struct TALER_Amount value; + json_t *json_history; + int ret; + const struct TALER_EXCHANGEDB_ReserveHistory *pos; + struct TALER_WithdrawRequestPS wr; + + json_history = json_array (); + ret = 0; + for (pos = rh; NULL != pos; pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + if (0 == ret) + deposit_total = pos->details.bank->amount; + else + if (GNUNET_OK != + TALER_amount_add (&deposit_total, + &deposit_total, + &pos->details.bank->amount)) + { + json_decref (json_history); + return NULL; + } + ret = 1; + json_array_append_new (json_history, + json_pack ("{s:s, s:O, s:o}", + "type", "DEPOSIT", + "wire", pos->details.bank->wire, + "amount", TALER_json_from_amount (&pos->details.bank->amount))); + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + break; + } + } + + ret = 0; + for (pos = rh; NULL != pos; pos = pos->next) + { + switch (pos->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + value = pos->details.withdraw->amount_with_fee; + if (0 == ret) + { + withdraw_total = value; + } + else + { + if (GNUNET_OK != + TALER_amount_add (&withdraw_total, + &withdraw_total, + &value)) + { + json_decref (json_history); + return NULL; + } + } + ret = 1; + wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); + wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); + wr.reserve_pub = pos->details.withdraw->reserve_pub; + TALER_amount_hton (&wr.amount_with_fee, + &value); + TALER_amount_hton (&wr.withdraw_fee, + &pos->details.withdraw->withdraw_fee); + GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key, + &wr.h_denomination_pub); + wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope; + json_array_append_new (json_history, + json_pack ("{s:s, s:o, s:o, s:o}", + "type", "WITHDRAW", + "signature", TALER_json_from_data (&pos->details.withdraw->reserve_sig, + sizeof (struct TALER_ReserveSignatureP)), + "details", TALER_json_from_data (&wr, + sizeof (wr)), + "amount", TALER_json_from_amount (&value))); + break; + } + } + if (0 == ret) + { + /* did not encounter any withdraw operations, set to zero */ + TALER_amount_get_zero (deposit_total.currency, + &withdraw_total); + } + if (GNUNET_SYSERR == + TALER_amount_subtract (balance, + &deposit_total, + &withdraw_total)) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + + return json_history; +} + + +/** + * Send reserve status information to client. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + json_t *json_balance; + json_t *json_history; + struct TALER_Amount balance; + + json_history = compile_reserve_history (rh, + &balance); + if (NULL == json_history) + return TMH_RESPONSE_reply_internal_error (connection, + "balance calculation failure"); + json_balance = TALER_json_from_amount (&balance); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o}", + "balance", json_balance, + "history", json_history); +} + + +/** + * Send reserve status information to client with the + * message that we have insufficient funds for the + * requested /reserve/withdraw operation. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + json_t *json_balance; + json_t *json_history; + struct TALER_Amount balance; + + json_history = compile_reserve_history (rh, + &balance); + if (NULL == json_history) + return TMH_RESPONSE_reply_internal_error (connection, + "balance calculation failure"); + json_balance = TALER_json_from_amount (&balance); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_PAYMENT_REQUIRED, + "{s:s, s:o, s:o}", + "error", "Insufficient funds", + "balance", json_balance, + "history", json_history); +} + + +/** + * Send blinded coin information to client. + * + * @param connection connection to the client + * @param collectable blinded coin to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) +{ + json_t *sig_json; + + sig_json = TALER_json_from_rsa_signature (collectable->sig.rsa_signature); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "ev_sig", sig_json); +} + + +/** + * Send a response for a failed "/refresh/melt" request. The + * transaction history of the given coin demonstrates that the + * @a residual value of the coin is below the @a requested + * contribution of the coin for the melt. Thus, the exchange + * refuses the melt operation. + * + * @param connection the connection to send the response to + * @param coin_pub public key of the coin + * @param coin_value original value of the coin + * @param tl transaction history for the coin + * @param requested how much this coin was supposed to contribute, including fee + * @param residual remaining value of the coin (after subtracting @a tl) + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct TALER_Amount coin_value, + struct TALER_EXCHANGEDB_TransactionList *tl, + struct TALER_Amount requested, + struct TALER_Amount residual) +{ + json_t *history; + + history = compile_transaction_history (tl); + if (NULL == history) + return TMH_RESPONSE_reply_internal_db_error (connection); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s, s:o, s:o, s:o, s:o, s:o}", + "error", + "insufficient funds", + "coin_pub", + TALER_json_from_data (coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)), + "original_value", + TALER_json_from_amount (&coin_value), + "residual_value", + TALER_json_from_amount (&residual), + "requested_value", + TALER_json_from_amount (&requested), + "history", + history); +} + + +/** + * Send a response to a "/refresh/melt" request. + * + * @param connection the connection to send the response to + * @param session_hash hash of the refresh session + * @param noreveal_index which index will the client not have to reveal + * @return a MHD status code + */ +int +TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + uint16_t noreveal_index) +{ + struct TALER_RefreshMeltConfirmationPS body; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + json_t *sig_json; + + body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS)); + body.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT); + body.session_hash = *session_hash; + body.noreveal_index = htons (noreveal_index); + body.reserved = htons (0); + TMH_KS_sign (&body.purpose, + &pub, + &sig); + sig_json = TALER_json_from_data (&sig, + sizeof (sig)); + GNUNET_assert (NULL != sig_json); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:i, s:o, s:o}", + "noreveal_index", (int) noreveal_index, + "exchange_sig", sig_json, + "exchange_pub", TALER_json_from_data (&pub, + sizeof (pub))); +} + + +/** + * Send a response for "/refresh/reveal". + * + * @param connection the connection to send the response to + * @param num_newcoins number of new coins for which we reveal data + * @param sigs array of @a num_newcoins signatures revealed + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection, + unsigned int num_newcoins, + const struct TALER_DenominationSignature *sigs) +{ + int newcoin_index; + json_t *root; + json_t *obj; + json_t *list; + int ret; + + list = json_array (); + for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++) + { + obj = json_object (); + json_object_set_new (obj, + "ev_sig", + TALER_json_from_rsa_signature (sigs[newcoin_index].rsa_signature)); + json_array_append_new (list, + obj); + } + root = json_object (); + json_object_set_new (root, + "ev_sigs", + list); + ret = TMH_RESPONSE_reply_json (connection, + root, + MHD_HTTP_OK); + json_decref (root); + return ret; +} + + +/** + * Send a response for a failed "/refresh/reveal", where the + * revealed value(s) do not match the original commitment. + * + * @param connection the connection to send the response to + * @param mc all information about the original commitment + * @param off offset in the array of kappa-commitments where + * the missmatch was detected + * @param j index of the coin for which the missmatch was + * detected + * @param missmatch_object name of the object that was + * bogus (i.e. "transfer key"). + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_MeltCommitment *mc, + unsigned int off, + unsigned int j, + const char *missmatch_object) +{ + json_t *info_old; + json_t *info_new; + json_t *info_commit; + json_t *info_links; + unsigned int i; + unsigned int k; + + info_old = json_array (); + for (i=0;i<mc->num_oldcoins;i++) + { + const struct TALER_EXCHANGEDB_RefreshMelt *rm; + json_t *rm_json; + + rm = &mc->melts[i]; + rm_json = json_object (); + json_object_set_new (rm_json, + "coin_sig", + TALER_json_from_data (&rm->coin_sig, + sizeof (struct TALER_CoinSpendSignatureP))); + json_object_set_new (rm_json, + "coin_pub", + TALER_json_from_data (&rm->coin.coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP))); + json_object_set_new (rm_json, + "melt_amount_with_fee", + TALER_json_from_amount (&rm->amount_with_fee)); + json_object_set_new (rm_json, + "melt_fee", + TALER_json_from_amount (&rm->melt_fee)); + json_array_append_new (info_old, + rm_json); + } + info_new = json_array (); + for (i=0;i<mc->num_newcoins;i++) + { + const struct TALER_DenominationPublicKey *pk; + + pk = &mc->denom_pubs[i]; + json_array_append_new (info_new, + TALER_json_from_rsa_public_key (pk->rsa_public_key)); + + } + info_commit = json_array (); + info_links = json_array (); + for (k=0;k<TALER_CNC_KAPPA;k++) + { + json_t *info_commit_k; + json_t *info_link_k; + + info_commit_k = json_array (); + for (i=0;i<mc->num_newcoins;i++) + { + const struct TALER_EXCHANGEDB_RefreshCommitCoin *cc; + json_t *cc_json; + + cc = &mc->commit_coins[k][i]; + cc_json = json_object (); + json_object_set_new (cc_json, + "coin_ev", + TALER_json_from_data (cc->coin_ev, + cc->coin_ev_size)); + json_object_set_new (cc_json, + "coin_priv_enc", + TALER_json_from_data (cc->refresh_link->coin_priv_enc, + sizeof (struct TALER_CoinSpendPrivateKeyP))); + json_object_set_new (cc_json, + "blinding_key_enc", + TALER_json_from_data (cc->refresh_link->blinding_key_enc, + cc->refresh_link->blinding_key_enc_size)); + + json_array_append_new (info_commit_k, + cc_json); + } + json_array_append_new (info_commit, + info_commit_k); + info_link_k = json_array (); + for (i=0;i<mc->num_oldcoins;i++) + { + const struct TALER_RefreshCommitLinkP *cl; + json_t *cl_json; + + cl = &mc->commit_links[k][i]; + cl_json = json_object (); + json_object_set_new (cl_json, + "transfer_pub", + TALER_json_from_data (&cl->transfer_pub, + sizeof (struct TALER_TransferPublicKeyP))); + json_object_set_new (cl_json, + "shared_secret_enc", + TALER_json_from_data (&cl->shared_secret_enc, + sizeof (struct TALER_EncryptedLinkSecretP))); + json_array_append_new (info_link_k, + cl_json); + } + json_array_append_new (info_links, + info_link_k); + } + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:i, s:i, s:o, s:o, s:o, s:o, s:s}", + "error", "commitment violation", + "offset", (int) off, + "index", (int) j, + "oldcoin_infos", info_old, + "newcoin_infos", info_new, + "commit_infos", info_commit, + "link_infos", info_links, + "object", missmatch_object); +} + + +/** + * Send a response for "/refresh/link". + * + * @param connection the connection to send the response to + * @param num_sessions number of sessions the coin was used in + * @param sessions array of @a num_session entries with + * information for each session + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, + unsigned int num_sessions, + const struct TMH_RESPONSE_LinkSessionInfo *sessions) +{ + json_t *root; + json_t *mlist; + int res; + unsigned int i; + + mlist = json_array (); + for (i=0;i<num_sessions;i++) + { + const struct TALER_EXCHANGEDB_LinkDataList *pos; + json_t *list = json_array (); + + for (pos = sessions[i].ldl; NULL != pos; pos = pos->next) + { + json_t *obj; + + obj = json_object (); + json_object_set_new (obj, + "link_enc", + TALER_json_from_data (pos->link_data_enc->coin_priv_enc, + sizeof (struct TALER_CoinSpendPrivateKeyP) + + pos->link_data_enc->blinding_key_enc_size)); + json_object_set_new (obj, + "denom_pub", + TALER_json_from_rsa_public_key (pos->denom_pub.rsa_public_key)); + json_object_set_new (obj, + "ev_sig", + TALER_json_from_rsa_signature (pos->ev_sig.rsa_signature)); + json_array_append_new (list, + obj); + } + root = json_object (); + json_object_set_new (root, + "new_coins", + list); + json_object_set_new (root, + "transfer_pub", + TALER_json_from_data (&sessions[i].transfer_pub, + sizeof (struct TALER_TransferPublicKeyP))); + json_object_set_new (root, + "secret_enc", + TALER_json_from_data (&sessions[i].shared_secret_enc, + sizeof (struct TALER_EncryptedLinkSecretP))); + json_array_append_new (mlist, + root); + } + res = TMH_RESPONSE_reply_json (connection, + mlist, + MHD_HTTP_OK); + json_decref (mlist); + return res; +} + + +/** + * A merchant asked for details about a deposit, but + * we do not know anything about the deposit. Generate the + * 404 reply. + * + * @param connection connection to the client + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "Deposit unknown"); +} + + +/** + * A merchant asked for details about a deposit, but + * we did not execute the deposit yet. Generate a 202 reply. + * + * @param connection connection to the client + * @param planned_exec_time planned execution time + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, + struct GNUNET_TIME_Absolute planned_exec_time) +{ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_ACCEPTED, + "{s:o}", + "execution_time", TALER_json_from_abs (planned_exec_time)); +} + + +/** + * A merchant asked for details about a deposit. Provide + * them. Generates the 200 reply. + * + * @param connection connection to the client + * @param h_contract hash of the contract + * @param h_wire hash of wire account details + * @param coin_pub public key of the coin + * @param coin_contribution how much did the coin we asked about + * contribute to the total transfer value? (deposit value minus fee) + * @param transaction_id merchant transaction identifier + * @param wtid raw wire transfer identifier + * @param exec_time execution time of the wire transfer + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_contribution, + uint64_t transaction_id, + const struct TALER_WireTransferIdentifierRawP *wtid, + struct GNUNET_TIME_Absolute exec_time) +{ + struct TALER_ConfirmWirePS cw; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + + cw.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE); + cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS)); + cw.h_wire = *h_wire; + cw.h_contract = *h_contract; + cw.wtid = *wtid; + cw.coin_pub = *coin_pub; + cw.transaction_id = GNUNET_htonll (transaction_id); + cw.execution_time = GNUNET_TIME_absolute_hton (exec_time); + TALER_amount_hton (&cw.coin_contribution, + coin_contribution); + TMH_KS_sign (&cw.purpose, + &pub, + &sig); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o, s:o, s:o}", + "wtid", TALER_json_from_data (wtid, + sizeof (*wtid)), + "execution_time", TALER_json_from_abs (exec_time), + "coin_contribution", TALER_json_from_amount (coin_contribution), + "exchange_sig", TALER_json_from_data (&sig, + sizeof (sig)), + "exchange_pub", TALER_json_from_data (&pub, + sizeof (pub))); +} + + +/** + * A merchant asked for transaction details about a wire transfer. + * Provide them. Generates the 200 reply. + * + * @param connection connection to the client + * @param total total amount that was transferred + * @param merchant_pub public key of the merchant + * @param h_wire destination account + * @param deposits details about the combined deposits + * @return MHD result code + */ +int +TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, + const struct TALER_Amount *total, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + json_t *deposits) +{ + /* FIXME: #4135: signing not implemented here */ + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o}", + "total", TALER_json_from_amount (total), + "merchant_pub", TALER_json_from_data (merchant_pub, + sizeof (struct TALER_MerchantPublicKeyP)), + "h_wire", TALER_json_from_data (h_wire, + sizeof (struct GNUNET_HashCode)), + "deposits", deposits); +} + + +/* end of taler-exchange-httpd_responses.c */ diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h new file mode 100644 index 000000000..817273a58 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -0,0 +1,469 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_responses.h + * @brief API for generating the various replies of the exchange; these + * functions are called TMH_RESPONSE_reply_ and they generate + * and queue MHD response objects for a given connection. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_RESPONSES_H +#define TALER_EXCHANGE_HTTPD_RESPONSES_H +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler-exchange-httpd.h" +#include "taler-exchange-httpd_db.h" + +/** + * Add headers we want to return in every response. + * Useful for testing, like if we want to always close + * connections. + * + * @param response response to modify + */ +void +TMH_RESPONSE_add_global_headers (struct MHD_Response *response); + + +/** + * Send JSON object as response. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TMH_RESPONSE_reply_json (struct MHD_Connection *connection, + const json_t *json, + unsigned int response_code); + + +/** + * Function to call to handle the request by building a JSON + * reply from a format string and varargs. + * + * @param connection the MHD connection to handle + * @param response_code HTTP response code to use + * @param fmt format string for pack + * @param ... varargs + * @return MHD result code + */ +int +TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...); + + +/** + * Send a response indicating an invalid signature. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, + const char *param_name); + + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return MHD result code + */ +int +TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name); + + +/** + * Send a response indicating an argument refering to a + * resource unknown to the exchange (i.e. unknown reserve or + * denomination key). + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, + const char *param_name); + + +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name); + + +/** + * Send a response indicating permission denied. + * + * @param connection the MHD connection to use + * @param hint hint about why access was denied + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, + const char *hint); + + +/** + * Send a response indicating an internal error. + * + * @param connection the MHD connection to use + * @param hint hint about the internal error's nature + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + const char *hint); + + +/** + * Send a response indicating an external error. + * + * @param connection the MHD connection to use + * @param hint hint about the error's nature + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + const char *hint); + + +/** + * Send a response indicating an error committing a + * transaction (concurrent interference). + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection); + + +/** + * Send a response indicating a failure to talk to the Exchange's + * database. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection); + + +/** + * Send a response indicating that the request was too big. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); + + +/** + * Send a response indicating that the JSON was malformed. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection); + + +/** + * Send confirmation of deposit success to client. This function + * will create a signed message affirming the given information + * and return it to the client. By this, the exchange affirms that + * the coin had sufficient (residual) value for the specified + * transaction and that it will execute the requested deposit + * operation with the given wiring details. + * + * @param connection connection to the client + * @param coin_pub public key of the coin + * @param h_wire hash of wire details + * @param h_contract hash of contract details + * @param transaction_id transaction ID + * @param timestamp client's timestamp + * @param refund_deadline until when this deposit be refunded + * @param merchant merchant public key + * @param amount_without_fee fraction of coin value to deposit (without fee) + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_MerchantPublicKeyP *merchant, + const struct TALER_Amount *amount_without_fee); + + +/** + * Send proof that a /deposit request is invalid to client. This + * function will create a message with all of the operations affecting + * the coin that demonstrate that the coin has insufficient value. + * + * @param connection connection to the client + * @param tl transaction list to use to build reply + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_TransactionList *tl); + + +/** + * A merchant asked for details about a deposit, but + * we do not know anything about the deposit. Generate the + * 404 reply. + * + * @param connection connection to the client + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection); + + +/** + * A merchant asked for details about a deposit, but + * we did not execute the deposit yet. Generate a 202 reply. + * + * @param connection connection to the client + * @param planned_exec_time planned execution time + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, + struct GNUNET_TIME_Absolute planned_exec_time); + + +/** + * A merchant asked for details about a deposit. Provide + * them. Generates the 200 reply. + * + * @param connection connection to the client + * @param h_contract hash of the contract + * @param h_wire hash of wire account details + * @param coin_pub public key of the coin + * @param coin_contribution contribution of this coin to the total amount transferred + * @param transaction_id merchant transaction identifier + * @param wtid raw wire transfer identifier + * @param exec_time execution time of the wire transfer + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_contribution, + uint64_t transaction_id, + const struct TALER_WireTransferIdentifierRawP *wtid, + struct GNUNET_TIME_Absolute exec_time); + + +/** + * A merchant asked for transaction details about a wire transfer. + * Provide them. Generates the 200 reply. + * + * @param connection connection to the client + * @param total total amount that was transferred + * @param merchant_pub public key of the merchant + * @param h_wire destination account + * @param deposits details about the combined deposits + * @return MHD result code + */ +int +TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, + const struct TALER_Amount *total, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + json_t *deposits); + + +/** + * Send reserve status information to client. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh); + + +/** + * Send reserve status information to client with the + * message that we have insufficient funds for the + * requested /reserve/withdraw operation. + * + * @param connection connection to the client + * @param rh reserve history to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_ReserveHistory *rh); + + +/** + * Send blinded coin information to client. + * + * @param connection connection to the client + * @param collectable blinded coin to return + * @return MHD result code + */ +int +TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable); + + +/** + * Send a confirmation response to a "/refresh/melt" request. + * + * @param connection the connection to send the response to + * @param session_hash hash of the refresh session + * @param noreveal_index which index will the client not have to reveal + * @return a MHD status code + */ +int +TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection, + const struct GNUNET_HashCode *session_hash, + uint16_t noreveal_index); + + +/** + * Send a response for a failed "/refresh/melt" request. The + * transaction history of the given coin demonstrates that the + * @a residual value of the coin is below the @a requested + * contribution of the coin for the melt. Thus, the exchange + * refuses the melt operation. + * + * @param connection the connection to send the response to + * @param coin_pub public key of the coin + * @param coin_value original value of the coin + * @param tl transaction history for the coin + * @param requested how much this coin was supposed to contribute + * @param residual remaining value of the coin (after subtracting @a tl) + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct TALER_Amount coin_value, + struct TALER_EXCHANGEDB_TransactionList *tl, + struct TALER_Amount requested, + struct TALER_Amount residual); + + +/** + * Send a response for "/refresh/reveal". + * + * @param connection the connection to send the response to + * @param num_newcoins number of new coins for which we reveal data + * @param sigs array of @a num_newcoins signatures revealed + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection, + unsigned int num_newcoins, + const struct TALER_DenominationSignature *sigs); + + +/** + * Send a response for a failed "/refresh/reveal", where the + * revealed value(s) do not match the original commitment. + * + * @param connection the connection to send the response to + * @param mc all information about the original commitment + * @param off offset in the array of kappa-commitments where + * the missmatch was detected + * @param j index of the coin for which the missmatch was + * detected + * @param missmatch_object name of the object that was + * bogus (i.e. "transfer key"). + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, + const struct TALER_EXCHANGEDB_MeltCommitment *mc, + unsigned int off, + unsigned int j, + const char *missmatch_object); + + +/** + * @brief Information for each session a coin was melted into. + */ +struct TMH_RESPONSE_LinkSessionInfo +{ + /** + * Transfer public key of the coin. + */ + struct TALER_TransferPublicKeyP transfer_pub; + + /** + * Encrypted shared secret for decrypting the transfer secrets. + */ + struct TALER_EncryptedLinkSecretP shared_secret_enc; + + /** + * Linked data of coins being created in the session. + */ + struct TALER_EXCHANGEDB_LinkDataList *ldl; + +}; + + +/** + * Send a response for "/refresh/link". + * + * @param connection the connection to send the response to + * @param num_sessions number of sessions the coin was used in + * @param sessions array of @a num_session entries with + * information for each session + * @return a MHD result code + */ +int +TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, + unsigned int num_sessions, + const struct TMH_RESPONSE_LinkSessionInfo *sessions); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_test.c b/src/exchange/taler-exchange-httpd_test.c new file mode 100644 index 000000000..876869d86 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_test.c @@ -0,0 +1,621 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_test.c + * @brief Handle /test requests; parses the POST and JSON and + * checks that the client is binary-compatible + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include "taler_signatures.h" +#include "taler-exchange-httpd_test.h" +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_responses.h" + + +/** + * Private key the test module uses for signing. + */ +static struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_pk; + + +/** + * Handle a "/test/base32" request. Parses the JSON in the post, runs + * the Crockford Base32 decoder on the "input" field in the JSON, + * hashes the result and sends the hashed value back as a JSON + * string with in Base32 Crockford encoding. Thus, this API + * allows testing the hashing and Crockford encoding/decoding + * functions. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + void *in_ptr; + size_t in_ptr_size; + struct GNUNET_HashCode hc; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + GNUNET_CRYPTO_hash (in_ptr, + in_ptr_size, + &hc); + TMH_PARSE_release_data (spec); + json_decref (json); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + TALER_json_from_data (&hc, sizeof (struct GNUNET_HashCode))); +} + + +/** + * Handle a "/test/encrypt" request. Parses the JSON in the post, + * runs the Crockford Base32 decoder on the "input" field in the JSON, + * and encrypts the result with a shared secret derived using the HKDF + * function with salt "skey" and IV derived with salt "iv" of the + * Crockford Base32-encoded "key_hash" field in the JSON. The + * symmetric encryption is the AES/Twofish double-encryption used in + * Taler/GNUnet. The resulting ciphertext is returned as a Crockford + * Base32 encoded JSON string. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct GNUNET_HashCode key; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + struct GNUNET_CRYPTO_SymmetricSessionKey skey; + void *in_ptr; + size_t in_ptr_size; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), + TMH_PARSE_member_fixed ("key_hash", &key), + TMH_PARSE_MEMBER_END + }; + char *out; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_kdf (&skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), + "skey", strlen ("skey"), + &key, sizeof (key), + NULL, 0)); + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_kdf (&iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector), + "iv", strlen ("iv"), + &key, sizeof (key), + NULL, 0)); + out = GNUNET_malloc (in_ptr_size); + GNUNET_break (in_ptr_size == + GNUNET_CRYPTO_symmetric_encrypt (in_ptr, + in_ptr_size, + &skey, + &iv, + out)); + json = TALER_json_from_data (out, + in_ptr_size); + GNUNET_free (out); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + json); +} + + +/** + * Handle a "/test/hkdf" request. Parses the JSON in the post, runs + * the Crockford Base32 decoder on the "input" field in the JSON, + * computes `HKDF(input, "salty")` and sends the result back as a JSON + * string with in Base32 Crockford encoding. Thus, this API allows + * testing the use of the (H)KDF. Note that the test fixes the + * input and output sizes and the salt (and the hash functions used + * by the HKDF), so this is only useful to test the HKDF in the + * same way it will be used within Taler/GNUnet. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct GNUNET_HashCode hc; + void *in_ptr; + size_t in_ptr_size; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + GNUNET_CRYPTO_kdf (&hc, sizeof (hc), + "salty", strlen ("salty"), + in_ptr, + in_ptr_size, + NULL, 0); + TMH_PARSE_release_data (spec); + json = TALER_json_from_data (&hc, + sizeof (struct GNUNET_HashCode)); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + json); +} + + +/** + * Handle a "/test/ecdhe" request. Parses the JSON in the post, which + * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv" + * with a private key. The reply is the resulting JSON is an object + * with the field "ecdh_hash" containing a Crockford Base32-encoded + * string representing the hash derived via ECDH of the two keys. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct GNUNET_CRYPTO_EcdhePublicKey pub; + struct GNUNET_CRYPTO_EcdhePrivateKey priv; + struct GNUNET_HashCode hc; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("ecdhe_pub", &pub), + TMH_PARSE_member_fixed ("ecdhe_priv", &priv), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + if (GNUNET_OK != + GNUNET_CRYPTO_ecc_ecdh (&priv, + &pub, + &hc)) + { + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to perform ECDH"); + } + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "ecdh_hash", + TALER_json_from_data (&hc, + sizeof (hc))); +} + + +/** + * Handle a "/test/eddsa" request. Parses the JSON in the post, + * which must contain a "eddsa_pub" with a public key and an + *"eddsa_sig" with the corresponding signature for a purpose + * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is + * valid, a reply with a #TALER_SIGNATURE_EXCHANGE_TEST_EDDSA is + * returned using the same JSON format. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("eddsa_pub", &pub), + TMH_PARSE_member_fixed ("eddsa_sig", &sig), + TMH_PARSE_MEMBER_END + }; + struct GNUNET_CRYPTO_EddsaPrivateKey *pk; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); + purpose.purpose = htonl (TALER_SIGNATURE_CLIENT_TEST_EDDSA); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_CLIENT_TEST_EDDSA, + &purpose, + &sig, + &pub)) + { + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_signature_invalid (connection, + "eddsa_sig"); + } + TMH_PARSE_release_data (spec); + pk = GNUNET_CRYPTO_eddsa_key_create (); + purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_TEST_EDDSA); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign (pk, + &purpose, + &sig)) + { + GNUNET_free (pk); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to EdDSA-sign"); + } + GNUNET_CRYPTO_eddsa_key_get_public (pk, + &pub); + GNUNET_free (pk); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o}", + "eddsa_pub", + TALER_json_from_data (&pub, + sizeof (pub)), + "eddsa_sig", + TALER_json_from_data (&sig, + sizeof (sig))); +} + + +/** + * Handle a "/test/rsa/get" request. Returns the RSA public key + * ("rsa_pub") which is used for signing in "/test/rsa/sign". + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + int res; + struct GNUNET_CRYPTO_rsa_PublicKey *pub; + + if (NULL == rsa_pk) + rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024); + if (NULL == rsa_pk) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to create RSA key"); + } + pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk); + if (NULL == pub) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to get public RSA key"); + } + res = TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "rsa_pub", + TALER_json_from_rsa_public_key (pub)); + GNUNET_CRYPTO_rsa_public_key_free (pub); + return res; +} + + +/** + * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which + * must contain an "blind_ev" blinded value. A a blinded signature + * ("rsa_blind_sig") is returned. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct GNUNET_CRYPTO_rsa_Signature *sig; + void *in_ptr; + size_t in_ptr_size; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_variable ("blind_ev", &in_ptr, &in_ptr_size), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + if (NULL == rsa_pk) + rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024); + if (NULL == rsa_pk) + { + GNUNET_break (0); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to create RSA key"); + } + sig = GNUNET_CRYPTO_rsa_sign (rsa_pk, + in_ptr, + in_ptr_size); + if (NULL == sig) + { + GNUNET_break (0); + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to RSA-sign"); + } + TMH_PARSE_release_data (spec); + res = TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "rsa_blind_sig", + TALER_json_from_rsa_signature (sig)); + GNUNET_CRYPTO_rsa_signature_free (sig); + return res; +} + + +/** + * Handle a "/test/transfer" request. Parses the JSON in the post, + * which must contain a "secret_enc" with the encrypted link secret, + * a "trans_priv" with the transfer private key, a "coin_pub" with + * a coin public key. A reply with the decrypted "secret" is + * returned. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + struct TALER_EncryptedLinkSecretP secret_enc; + struct TALER_TransferPrivateKeyP trans_priv; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("secret_enc", &secret_enc), + TMH_PARSE_member_fixed ("trans_priv", &trans_priv), + TMH_PARSE_member_fixed ("coin_pub", &coin_pub), + TMH_PARSE_MEMBER_END + }; + struct TALER_LinkSecretP secret; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + json_decref (json); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + if (GNUNET_OK != + TALER_link_decrypt_secret (&secret_enc, + &trans_priv, + &coin_pub, + &secret)) + { + TMH_PARSE_release_data (spec); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to decrypt secret"); + } + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "secret", + TALER_json_from_data (&secret, + sizeof (secret))); +} + + +/** + * Handle a "/test" request. Parses the JSON in the post. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *json; + int res; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + + json_decref (json); + return MHD_NO; +} + + +/* end of taler-exchange-httpd_test.c */ diff --git a/src/exchange/taler-exchange-httpd_test.h b/src/exchange/taler-exchange-httpd_test.h new file mode 100644 index 000000000..30535f54f --- /dev/null +++ b/src/exchange/taler-exchange-httpd_test.h @@ -0,0 +1,225 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_test.h + * @brief Handle /test requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_TEST_H +#define TALER_EXCHANGE_HTTPD_TEST_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/test/base32" request. Parses the JSON in the post, runs + * the Crockford Base32 decoder on the "input" field in the JSON, + * hashes the result and sends the hashed value back as a JSON + * string with in Base32 Crockford encoding. Thus, this API + * allows testing the hashing and Crockford encoding/decoding + * functions. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/encrypt" request. Parses the JSON in the post, + * runs the Crockford Base32 decoder on the "input" field in the JSON, + * and encrypts the result with a shared secret derived using the HKDF + * function with salt "skey" and IV derived with salt "iv" of the + * Crockford Base32-encoded "key_hash" field in the JSON. The + * symmetric encryption is the AES/Twofish double-encryption used in + * Taler/GNUnet. The resulting ciphertext is returned as a Crockford + * Base32 encoded JSON string. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/hkdf" request. Parses the JSON in the post, runs + * the Crockford Base32 decoder on the "input" field in the JSON, + * computes `HKDF(input, "salty")` and sends the result back as a JSON + * string with in Base32 Crockford encoding. Thus, this API allows + * testing the use of the (H)KDF. Note that the test fixes the + * input and output sizes and the salt (and the hash functions used + * by the HKDF), so this is only useful to test the HKDF in the + * same way it will be used within Taler/GNUnet. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/ecdhe" request. Parses the JSON in the post, which + * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv" + * with a private key. The reply is the resulting JSON is an object + * with the field "ecdh_hash" containing a Crockford Base32-encoded + * string representing the hash derived via ECDH of the two keys. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/eddsa" request. Parses the JSON in the post, + * which must contain a "eddsa_pub" with a public key and an + *"ecdsa_sig" with the corresponding signature for a purpose + * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is + * valid, a reply with a #TALER_SIGNATURE_EXCHANGE_TEST_EDDSA is + * returned using the same JSON format. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/rsa/get" request. Returns the RSA public key + * ("rsa_pub") which is used for signing in "/test/rsa/sign". + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which + * must contain an "blind_ev" blinded value. A a blinded signature + * ("rsa_blind_sig") is returned. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test/transfer" request. Parses the JSON in the post, + * which must contain a "secret_enc" with the encrypted link secret, + * a "trans_priv" with the transfer private key, a "coin_pub" with + * a coin public key. A reply with the decrypted "secret" is + * returned. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/test" request. Parses the JSON in the post. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TEST_handler_test (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + +#endif diff --git a/src/exchange/taler-exchange-httpd_tracking.c b/src/exchange/taler-exchange-httpd_tracking.c new file mode 100644 index 000000000..afb821cb9 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_tracking.c @@ -0,0 +1,165 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_tracking.c + * @brief Handle wire transfer tracking-related requests + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler_signatures.h" +#include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_tracking.h" +#include "taler-exchange-httpd_responses.h" + + +/** + * Handle a "/wire/deposits" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TALER_WireTransferIdentifierRawP wtid; + int res; + + res = TMH_PARSE_mhd_request_arg_data (connection, + "wtid", + &wtid, + sizeof (struct TALER_WireTransferIdentifierRawP)); + if (GNUNET_SYSERR == res) + return MHD_NO; /* internal error */ + if (GNUNET_NO == res) + return MHD_YES; /* parse error */ + return TMH_DB_execute_wire_deposits (connection, + &wtid); +} + + +/** + * Check the merchant signature, and if it is valid, + * return the wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param tps signed request to execute + * @param merchant_pub public key from the merchant + * @param merchant_sig signature from the merchant (to be checked) + * @param transaction_id transaction ID (in host byte order) + * @return MHD result code + */ +static int +check_and_handle_deposit_wtid_request (struct MHD_Connection *connection, + const struct TALER_DepositTrackPS *tps, + struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_MerchantSignatureP *merchant_sig, + uint64_t transaction_id) +{ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID, + &tps->purpose, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return TMH_RESPONSE_reply_signature_invalid (connection, + "merchant_sig"); + } + return TMH_DB_execute_deposit_wtid (connection, + &tps->h_contract, + &tps->h_wire, + &tps->coin_pub, + merchant_pub, + transaction_id); +} + + +/** + * Handle a "/deposit/wtid" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + int res; + json_t *json; + struct TALER_DepositTrackPS tps; + uint64_t transaction_id; + struct TALER_MerchantSignatureP merchant_sig; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("H_wire", &tps.h_wire), + TMH_PARSE_member_fixed ("H_contract", &tps.h_contract), + TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub), + TMH_PARSE_member_uint64 ("transaction_id", &transaction_id), + TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant), + TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + if (GNUNET_OK != res) + { + json_decref (json); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS)); + tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID); + tps.transaction_id = GNUNET_htonll (transaction_id); + res = check_and_handle_deposit_wtid_request (connection, + &tps, + &tps.merchant, + &merchant_sig, + transaction_id); + TMH_PARSE_release_data (spec); + json_decref (json); + return res; +} + + +/* end of taler-exchange-httpd_tracking.c */ diff --git a/src/exchange/taler-exchange-httpd_tracking.h b/src/exchange/taler-exchange-httpd_tracking.h new file mode 100644 index 000000000..d77de460a --- /dev/null +++ b/src/exchange/taler-exchange-httpd_tracking.h @@ -0,0 +1,65 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_tracking.h + * @brief Handle wire transfer tracking-related requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_TRACKING_H +#define TALER_EXCHANGE_HTTPD_TRACKING_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/wire/deposits" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/deposit/wtid" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c new file mode 100644 index 000000000..9132e3e02 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_validation.c @@ -0,0 +1,231 @@ +/* + This file is part of TALER + Copyright (C) 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_validation.c + * @brief helpers for calling the wire plugins to validate addresses + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler-exchange-httpd_validation.h" +#include "taler_wire_plugin.h" + + +/** + * Information we keep for each plugin. + */ +struct Plugin +{ + + /** + * We keep plugins in a DLL. + */ + struct Plugin *next; + + /** + * We keep plugins in a DLL. + */ + struct Plugin *prev; + + /** + * Type of the wireformat. + */ + char *type; + + /** + * Pointer to the plugin. + */ + struct TALER_WIRE_Plugin *plugin; + +}; + +/** + * Head of DLL of wire plugins. + */ +static struct Plugin *wire_head; + +/** + * Tail of DLL of wire plugins. + */ +static struct Plugin *wire_tail; + + +/** + * Initialize validation subsystem. + * + * @param cfg configuration to use + * @return #GNUNET_OK on success + */ +int +TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct Plugin *p; + char *wireformats; + char *lib_name; + const char *token; + + /* Find out list of supported wire formats */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "wireformat", + &wireformats)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "wireformat"); + return GNUNET_SYSERR; + } + for (token = strtok (wireformats, + " "); + NULL != token; + token = strtok (NULL, + " ")) + { + (void) GNUNET_asprintf (&lib_name, + "libtaler_plugin_wire_%s", + token); + p = GNUNET_new (struct Plugin); + p->type = GNUNET_strdup (token); + p->plugin = GNUNET_PLUGIN_load (lib_name, + (void *) cfg); + if (NULL == p->plugin) + { + GNUNET_free (p); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to load plugin %s\n", + lib_name); + GNUNET_free (lib_name); + TMH_VALIDATION_done (); + return GNUNET_SYSERR; + } + p->plugin->library_name = lib_name; + GNUNET_CONTAINER_DLL_insert (wire_head, + wire_tail, + p); + } + GNUNET_free (wireformats); + return GNUNET_OK; +} + + +/** + * Shutdown validation subsystem. + */ +void +TMH_VALIDATION_done () +{ + struct Plugin *p; + char *lib_name; + + while (NULL != (p = wire_head)) + { + GNUNET_CONTAINER_DLL_remove (wire_head, + wire_tail, + p); + lib_name = p->plugin->library_name; + GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, + p->plugin)); + GNUNET_free (lib_name); + GNUNET_free (p->type); + GNUNET_free (p); + } +} + + +/** + * Check if the given wire format JSON object is correctly formatted as + * a wire address. + * + * @param wire the JSON wire format object + * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not + */ +int +TMH_json_validate_wireformat (const json_t *wire) +{ + const char *stype; + json_error_t error; + struct Plugin *p; + + if (0 != json_unpack_ex ((json_t *) wire, + &error, 0, + "{s:s}", + "type", &stype)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + for (p=wire_head; NULL != p; p = p->next) + if (0 == strcasecmp (p->type, + stype)) + return p->plugin->wire_validate (wire); + return GNUNET_NO; +} + + +/** + * Check if we support the given wire method. + * + * @param type type of wire method to check + * @return #GNUNET_YES if the method is supported + */ +int +TMH_VALIDATION_test_method (const char *type) +{ + struct Plugin *p; + + for (p=wire_head;NULL != p;p = p->next) + if (0 == strcasecmp (type, + p->type)) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Obtain supported validation methods as a JSON array, + * and as a hash. + * + * @param[out] h set to the hash of the JSON methods + * @return JSON array with the supported validation methods + */ +json_t * +TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h) +{ + json_t *methods; + struct GNUNET_HashContext *hc; + const char *wf; + struct Plugin *p; + + methods = json_array (); + hc = GNUNET_CRYPTO_hash_context_start (); + for (p=wire_head;NULL != p;p = p->next) + { + wf = p->type; + json_array_append_new (methods, + json_string (wf)); + GNUNET_CRYPTO_hash_context_read (hc, + wf, + strlen (wf) + 1); + } + GNUNET_CRYPTO_hash_context_finish (hc, + h); + return methods; +} + + +/* end of taler-exchange-httpd_validation.c */ diff --git a/src/exchange/taler-exchange-httpd_validation.h b/src/exchange/taler-exchange-httpd_validation.h new file mode 100644 index 000000000..f41e2ee5f --- /dev/null +++ b/src/exchange/taler-exchange-httpd_validation.h @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-exchange-httpd_validation.h + * @brief helpers for calling the wire plugins to validate addresses + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_VALIDATION_H +#define TALER_EXCHANGE_HTTPD_VALIDATION_H +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> + + +/** + * Initialize validation subsystem. + * + * @param cfg configuration to use + * @return #GNUNET_OK on success + */ +int +TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Shutdown validation subsystem. + */ +void +TMH_VALIDATION_done (void); + + +/** + * Check if the given wire format JSON object is correctly formatted as + * a wire address. + * + * @param wire the JSON wire format object + * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not + */ +int +TMH_json_validate_wireformat (const json_t *wire); + +/** + * Check if we support the given wire method. + * + * @param type type of wire method to check + * @return #GNUNET_YES if the method is supported + */ +int +TMH_VALIDATION_test_method (const char *type); + + +/** + * Obtain supported validation methods as a JSON array, + * and as a hash. + * + * @param[out] h set to the hash of the JSON methods + * @return JSON array with the supported validation methods + */ +json_t * +TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h); + + +#endif diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c new file mode 100644 index 000000000..ba763b64d --- /dev/null +++ b/src/exchange/taler-exchange-httpd_wire.c @@ -0,0 +1,220 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_wire.c + * @brief Handle /wire requests + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-exchange-httpd_keystate.h" +#include "taler-exchange-httpd_responses.h" +#include "taler-exchange-httpd_validation.h" +#include "taler-exchange-httpd_wire.h" +#include <jansson.h> + +/** + * Handle a "/wire" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TALER_ExchangeWireSupportMethodsPS wsm; + struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP sig; + json_t *methods; + + wsm.purpose.size = htonl (sizeof (wsm)); + wsm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_WIRE_TYPES); + methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types); + TMH_KS_sign (&wsm.purpose, + &pub, + &sig); + return TMH_RESPONSE_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o}", + "methods", methods, + "sig", TALER_json_from_data (&sig, + sizeof (sig)), + "pub", TALER_json_from_data (&pub, + sizeof (pub))); +} + + +/** + * Handle a "/wire/test" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct MHD_Response *response; + int ret; + char *wire_test_redirect; + + response = MHD_create_response_from_buffer (0, NULL, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (response); + if (GNUNET_NO == TMH_VALIDATION_test_method ("test")) + { + /* Return 501: not implemented */ + ret = MHD_queue_response (connection, + MHD_HTTP_NOT_IMPLEMENTED, + response); + MHD_destroy_response (response); + return ret; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange-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, + "exchange-wire-sepa", + "SEPA_RESPONSE_FILE", + &sepa_wire_file)) + { + return TMH_RESPONSE_reply_internal_error (connection, + "SEPA_RESPONSE_FILE not configured"); + } + fd = open (sepa_wire_file, + O_RDONLY); + if (-1 == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "open", + sepa_wire_file); + GNUNET_free (sepa_wire_file); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to open SEPA_RESPONSE_FILE"); + } + if (0 != fstat (fd, &sbuf)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "fstat", + sepa_wire_file); + (void) close (fd); + GNUNET_free (sepa_wire_file); + return TMH_RESPONSE_reply_internal_error (connection, + "Failed to open SEPA_RESPONSE_FILE"); + } + response = MHD_create_response_from_fd ((size_t) sbuf.st_size, + fd); + GNUNET_free (sepa_wire_file); + if (NULL == response) + { + (void) close (fd); + GNUNET_break (0); + return MHD_NO; + } + TMH_RESPONSE_add_global_headers (response); + if (NULL != rh->mime_type) + (void) MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + rh->mime_type); + ret = MHD_queue_response (connection, + rh->response_code, + response); + MHD_destroy_response (response); + return ret; +} + +/* end of taler-exchange-httpd_wire.c */ diff --git a/src/exchange/taler-exchange-httpd_wire.h b/src/exchange/taler-exchange-httpd_wire.h new file mode 100644 index 000000000..dc6dcc0f4 --- /dev/null +++ b/src/exchange/taler-exchange-httpd_wire.h @@ -0,0 +1,82 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-exchange-httpd_wire.h + * @brief Handle /wire requests + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_WIRE_H +#define TALER_EXCHANGE_HTTPD_WIRE_H + +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * Handle a "/wire" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/wire/test" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +/** + * Handle a "/wire/sepa" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + +#endif diff --git a/src/mint/test-mint-home/master.priv b/src/exchange/test-exchange-home/master.priv index 394926938..394926938 100644 --- a/src/mint/test-mint-home/master.priv +++ b/src/exchange/test-exchange-home/master.priv diff --git a/src/exchange/test_taler_exchange_httpd.sh b/src/exchange/test_taler_exchange_httpd.sh new file mode 100644 index 000000000..c8df7cb9f --- /dev/null +++ b/src/exchange/test_taler_exchange_httpd.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# This file is part of TALER +# Copyright (C) 2015 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +# +# +# This script uses 'curl' to POST various ill-formed requests to the +# taler-exchange-httpd. Basically, the goal is to make sure that the +# HTTP server survives (and produces the 'correct' error code). +# +# We read the JSON snippets to POST from test_taler_exchange_httpd.data +# +# Setup keys. +taler-exchange-keyup -d test-exchange-home -m test-exchange-home/master.priv +# Run Exchange HTTPD (in background) +taler-exchange-httpd -d test-exchange-home & +# Give HTTP time to start +sleep 2 +# Run test... +cat test_taler_exchange_httpd.data | grep -v ^\# | awk '{ print "curl -d '\''" $2 "'\'' http://localhost:8081"$1 }' | bash +# Stop HTTP server +kill -TERM %% +# FIXME: not sure this is the 'correct' return code... +exit $? diff --git a/src/exchange/test_taler_exchange_httpd_afl.sh b/src/exchange/test_taler_exchange_httpd_afl.sh new file mode 100644 index 000000000..48beda722 --- /dev/null +++ b/src/exchange/test_taler_exchange_httpd_afl.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# This file is part of TALER +# Copyright (C) 2015 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# TALER is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +# +# +# This script uses 'curl' to POST various ill-formed requests to the +# taler-exchange-httpd. Basically, the goal is to make sure that the +# HTTP server survives (and produces the 'correct' error code). +# +# We read the JSON snippets from afl-tests/ +# +PREFIX= +# Uncomment this line to run with valgrind... +PREFIX="valgrind --leak-check=yes --log-file=valgrind.%p" +# Setup keys. +taler-exchange-keyup -d test-exchange-home -m test-exchange-home/master.priv +# Setup database (just to be sure) +taler-exchange-dbinit -d test-exchange-home &> /dev/null || true +# Only log hard errors, we expect lots of warnings... +export GNUNET_FORCE_LOG="taler-exchange-httpd;;;;ERROR/libmicrohttpd;;;;ERROR/util;;;;ERROR/" +# Run test... +for n in afl-tests/* +do + echo -n "Test $n " + $PREFIX taler-exchange-httpd -d test-exchange-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; } +# $PREFIX taler-exchange-httpd -d test-exchange-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; exit 1; } + echo "OK" +done +exit 0 diff --git a/src/exchange/test_taler_mint_httpd.data b/src/exchange/test_taler_mint_httpd.data new file mode 100644 index 000000000..43aa4ff05 --- /dev/null +++ b/src/exchange/test_taler_mint_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/exchangedb/Makefile.am b/src/exchangedb/Makefile.am new file mode 100644 index 000000000..d56d6676a --- /dev/null +++ b/src/exchangedb/Makefile.am @@ -0,0 +1,110 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS) + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +plugindir = $(libdir)/taler + +if HAVE_POSTGRESQL +plugin_LTLIBRARIES = \ + libtaler_plugin_exchangedb_postgres.la +endif + +EXTRA_DIST = \ + plugin_exchangedb_common.c \ + test-exchange-db-postgres.conf + +libtaler_plugin_exchangedb_postgres_la_SOURCES = \ + plugin_exchangedb_postgres.c +libtaler_plugin_exchangedb_postgres_la_LIBADD = \ + $(LTLIBINTL) +libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \ + $(TALER_PLUGIN_LDFLAGS) \ + $(top_builddir)/src/pq/libtalerpq.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lpq \ + -lgnunetpq \ + -lgnunetutil $(XLIB) + +lib_LTLIBRARIES = \ + libtalerexchangedb.la + +libtalerexchangedb_la_SOURCES = \ + exchangedb_keyio.c \ + exchangedb_plugin.c + +libtalerexchangedb_la_LIBADD = \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil $(XLIB) + +libtalerexchangedb_la_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) \ + -version-info 0:0:0 \ + -no-undefined + + +check_PROGRAMS = \ + test-exchangedb-deposits \ + test-exchangedb-keyio \ + test-exchangedb-postgres \ + test-perf-taler-exchangedb \ + perf-exchangedb + +TESTS = \ + test-exchangedb-postgres \ + test-perf-taler-exchangedb + +test_exchangedb_deposits_SOURCES = \ + test_exchangedb_deposits.c +test_exchangedb_deposits_LDADD = \ + libtalerexchangedb.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -lgnunetutil \ + -ljansson \ + -lpq + +test_exchangedb_keyio_SOURCES = \ + test_exchangedb_keyio.c +test_exchangedb_keyio_LDADD = \ + libtalerexchangedb.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -lgnunetutil + +test_exchangedb_postgres_SOURCES = \ + test_exchangedb.c +test_exchangedb_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -lgnunetutil -ljansson + +test_perf_taler_exchangedb_SOURCES = \ + test_perf_taler_exchangedb.c \ + perf_taler_exchangedb_init.c \ + perf_taler_exchangedb_interpreter.c +test_perf_taler_exchangedb_LDADD = \ + libtalerexchangedb.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -ljansson \ + -lgnunetutil + +perf_exchangedb_SOURCES = \ + perf_taler_exchangedb.c \ + perf_taler_exchangedb_init.c \ + perf_taler_exchangedb_interpreter.c +perf_exchangedb_LDADD = \ + libtalerexchangedb.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -ljansson \ + -lgnunetutil + + +EXTRA_test_exchangedb_postgres_DEPENDENCIES = \ + libtaler_plugin_exchangedb_postgres.la diff --git a/src/exchangedb/exchangedb_keyio.c b/src/exchangedb/exchangedb_keyio.c new file mode 100644 index 000000000..6b8ca24e3 --- /dev/null +++ b/src/exchangedb/exchangedb_keyio.c @@ -0,0 +1,558 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchangedb/exchangedb_keyio.c + * @brief I/O operations for the Exchange's private keys + * @author Florian Dold + * @author Benedikt Mueller + * @author Sree Harsha Totakura + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" + + +/** + * Closure for the #signkeys_iterate_dir_iter(). + */ +struct SignkeysIterateContext +{ + + /** + * Function to call on each signing key. + */ + TALER_EXCHANGEDB_SigningKeyIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; +}; + + +/** + * Function called on each file in the directory with our signing + * keys. Parses the file and calls the iterator from @a cls. + * + * @param cls the `struct SignkeysIterateContext *` + * @param filename name of the file to parse + * @return #GNUNET_OK to continue, + * #GNUNET_NO to stop iteration without error, + * #GNUNET_SYSERR to stop iteration with error + */ +static int +signkeys_iterate_dir_iter (void *cls, + const char *filename) +{ + struct SignkeysIterateContext *skc = cls; + ssize_t nread; + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP issue; + + nread = GNUNET_DISK_fn_read (filename, + &issue, + sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)); + if (nread != sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid signkey file `%s': wrong size (%d, expected %u)\n", + filename, + (int) nread, + sizeof (struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP)); + return GNUNET_OK; + } + return skc->it (skc->it_cls, + filename, + &issue); +} + + +/** + * Call @a it for each signing key found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_SIGNING_KEYS + * subdirectory + * @param it function to call on each signing key + * @param it_cls closure for @a it + * @return number of files found (may not match + * number of keys given to @a it as malformed + * files are simply skipped), -1 on error + */ +int +TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_SigningKeyIterator it, + void *it_cls) +{ + char *signkey_dir; + struct SignkeysIterateContext skc; + int ret; + + GNUNET_asprintf (&signkey_dir, + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_SIGNING_KEYS, + exchange_base_dir); + skc.it = it; + skc.it_cls = it_cls; + ret = GNUNET_DISK_directory_scan (signkey_dir, + &signkeys_iterate_dir_iter, + &skc); + GNUNET_free (signkey_dir); + return ret; +} + + +/** + * Import a denomination key from the given file. + * + * @param filename the file to import the key from + * @param[out] dki set to the imported denomination key + * @return #GNUNET_OK upon success; + * #GNUNET_SYSERR upon failure + */ +int +TALER_EXCHANGEDB_denomination_key_read (const char *filename, + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + uint64_t size; + size_t offset; + void *data; + struct GNUNET_CRYPTO_rsa_PrivateKey *priv; + + if (GNUNET_OK != GNUNET_DISK_file_size (filename, + &size, + GNUNET_YES, + GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping inaccessable denomination key file `%s'\n", + filename); + return GNUNET_SYSERR; + } + offset = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP); + if (size <= offset) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + data = GNUNET_malloc (size); + if (size != + GNUNET_DISK_fn_read (filename, + data, + size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "read", + filename); + GNUNET_free (data); + return GNUNET_SYSERR; + } + if (NULL == + (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset, + size - offset))) + { + GNUNET_free (data); + return GNUNET_SYSERR; + } + GNUNET_assert (NULL == dki->denom_priv.rsa_private_key); + dki->denom_priv.rsa_private_key = priv; + dki->denom_pub.rsa_public_key + = GNUNET_CRYPTO_rsa_private_key_get_public (priv); + memcpy (&dki->issue, + data, + offset); + GNUNET_free (data); + return GNUNET_OK; +} + + +/** + * Exports a denomination key to the given file. + * + * @param filename the file where to write the denomination key + * @param dki the denomination key + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. + */ +int +TALER_EXCHANGEDB_denomination_key_write (const char *filename, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + char *priv_enc; + size_t priv_enc_size; + struct GNUNET_DISK_FileHandle *fh; + ssize_t wrote; + size_t wsize; + int ret; + + fh = NULL; + priv_enc_size + = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key, + &priv_enc); + ret = GNUNET_SYSERR; + if (NULL == (fh = GNUNET_DISK_file_open + (filename, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) + goto cleanup; + wsize = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP); + if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, + &dki->issue, + wsize))) + goto cleanup; + if (wrote != wsize) + goto cleanup; + if (GNUNET_SYSERR == + (wrote = GNUNET_DISK_file_write (fh, + priv_enc, + priv_enc_size))) + goto cleanup; + if (wrote != priv_enc_size) + goto cleanup; + ret = GNUNET_OK; + cleanup: + GNUNET_free_non_null (priv_enc); + if (NULL != fh) + (void) GNUNET_DISK_file_close (fh); + return ret; +} + + +/** + * Closure for #denomkeys_iterate_keydir_iter() and + * #denomkeys_iterate_topdir_iter(). + */ +struct DenomkeysIterateContext +{ + + /** + * Set to the name of the directory below the top-level directory + * during the call to #denomkeys_iterate_keydir_iter(). + */ + const char *alias; + + /** + * Function to call on each denomination key. + */ + TALER_EXCHANGEDB_DenominationKeyIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; +}; + + +/** + * Decode the denomination key in the given file @a filename and call + * the callback in @a cls with the information. + * + * @param cls the `struct DenomkeysIterateContext *` + * @param filename name of a file that should contain + * a denomination key + * @return #GNUNET_OK to continue to iterate + * #GNUNET_NO to abort iteration with success + * #GNUNET_SYSERR to abort iteration with failure + */ +static int +denomkeys_iterate_keydir_iter (void *cls, + const char *filename) +{ + struct DenomkeysIterateContext *dic = cls; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue; + int ret; + + memset (&issue, 0, sizeof (issue)); + if (GNUNET_OK != + TALER_EXCHANGEDB_denomination_key_read (filename, + &issue)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid denomkey file: '%s'\n", + filename); + return GNUNET_OK; + } + ret = dic->it (dic->it_cls, + dic->alias, + &issue); + GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key); + return ret; +} + + +/** + * Function called on each subdirectory in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS. Will + * call the #denomkeys_iterate_keydir_iter() on each file in the + * subdirectory. + * + * @param cls the `struct DenomkeysIterateContext *` + * @param filename name of the subdirectory to scan + * @return #GNUNET_OK on success, + * #GNUNET_SYSERR if we need to abort + */ +static int +denomkeys_iterate_topdir_iter (void *cls, + const char *filename) +{ + struct DenomkeysIterateContext *dic = cls; + + dic->alias = GNUNET_STRINGS_get_short_name (filename); + if (0 > GNUNET_DISK_directory_scan (filename, + &denomkeys_iterate_keydir_iter, + dic)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Call @a it for each denomination key found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS + * subdirectory + * @param it function to call on each denomination key found + * @param it_cls closure for @a it + * @return -1 on error, 0 if no files were found, otherwise + * a positive number (however, even with a positive + * number it is possible that @a it was never called + * as maybe none of the files were well-formed) + */ +int +TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_DenominationKeyIterator it, + void *it_cls) +{ + char *dir; + struct DenomkeysIterateContext dic; + int ret; + + GNUNET_asprintf (&dir, + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, + exchange_base_dir); + dic.it = it; + dic.it_cls = it_cls; + ret = GNUNET_DISK_directory_scan (dir, + &denomkeys_iterate_topdir_iter, + &dic); + GNUNET_free (dir); + return ret; +} + + +/** + * Closure for #auditor_iter() and + */ +struct AuditorIterateContext +{ + + /** + * Function to call with the information for each auditor. + */ + TALER_EXCHANGEDB_AuditorIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Header of a file with auditing information. + */ +struct AuditorFileHeaderP +{ + + /** + * Public key of the auditor. + */ + struct TALER_AuditorPublicKeyP apub; + + /** + * Master public key of the exchange the auditor is signing + * information for. + */ + struct TALER_MasterPublicKeyP mpub; + +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Load the auditor signature and the information signed by the + * auditor and call the callback in @a cls with the information. + * + * @param cls the `struct AuditorIterateContext *` + * @param filename name of a file that should contain + * a denomination key + * @return #GNUNET_OK to continue to iterate + * #GNUNET_NO to abort iteration with success + * #GNUNET_SYSERR to abort iteration with failure + */ +static int +auditor_iter (void *cls, + const char *filename) +{ + struct AuditorIterateContext *aic = cls; + uint64_t size; + struct AuditorFileHeaderP *af; + const struct TALER_AuditorSignatureP *sigs; + const struct TALER_DenominationKeyValidityPS *dki; + unsigned int len; + int ret; + + if (GNUNET_OK != GNUNET_DISK_file_size (filename, + &size, + GNUNET_YES, + GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping inaccessable auditor information file `%s'\n", + filename); + return GNUNET_SYSERR; + } + if ( (size < sizeof (struct AuditorFileHeaderP)) || + (0 != (len = ((size - sizeof (struct AuditorFileHeaderP)) % + (sizeof (struct TALER_DenominationKeyValidityPS) + + sizeof (struct TALER_AuditorSignatureP))))) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + af = GNUNET_malloc (size); + if (size != + GNUNET_DISK_fn_read (filename, + af, + size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "read", + filename); + GNUNET_free (af); + return GNUNET_SYSERR; + } + sigs = (const struct TALER_AuditorSignatureP *) &af[1]; + dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[len]; + ret = aic->it (aic->it_cls, + &af->apub, + &af->mpub, + len, + sigs, + dki); + GNUNET_free (af); + return ret; +} + + +/** + * Call @a it with information for each auditor found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS + * subdirectory + * @param it function to call with auditor information + * @param it_cls closure for @a it + * @return -1 on error, 0 if no files were found, otherwise + * a positive number (however, even with a positive + * number it is possible that @a it was never called + * as maybe none of the files were well-formed) + */ +int +TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_AuditorIterator it, + void *it_cls) +{ + char *dir; + struct AuditorIterateContext aic; + int ret; + + GNUNET_asprintf (&dir, + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_AUDITORS, + exchange_base_dir); + aic.it = it; + aic.it_cls = it_cls; + ret = GNUNET_DISK_directory_scan (dir, + &auditor_iter, + &aic); + GNUNET_free (dir); + return ret; +} + + +/** + * Write auditor information to the given file. + * + * @param filename the file where to write the auditor information to + * @param apub the auditor's public key + * @param asigs the auditor's signatures, array of length @a dki_len + * @param mpub the exchange's public key (as expected by the auditor) + * @param dki_len length of @a dki + * @param dki array of denomination coin data signed by the auditor + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. + */ +int +TALER_EXCHANGEDB_auditor_write (const char *filename, + const struct TALER_AuditorPublicKeyP *apub, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_DenominationKeyValidityPS *dki) +{ + struct AuditorFileHeaderP af; + struct GNUNET_DISK_FileHandle *fh; + ssize_t wrote; + size_t wsize; + int ret; + int eno; + + af.apub = *apub; + af.mpub = *mpub; + ret = GNUNET_SYSERR; + if (NULL == (fh = GNUNET_DISK_file_open + (filename, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) + goto cleanup; + wsize = sizeof (struct AuditorFileHeaderP); + if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, + &af, + wsize))) + goto cleanup; + if (wrote != wsize) + goto cleanup; + wsize = dki_len * sizeof (struct TALER_AuditorSignatureP); + if (wsize == + GNUNET_DISK_file_write (fh, + asigs, + wsize)) + ret = GNUNET_OK; + wsize = dki_len * sizeof (struct TALER_DenominationKeyValidityPS); + if (wsize == + GNUNET_DISK_file_write (fh, + dki, + wsize)) + ret = GNUNET_OK; + cleanup: + eno = errno; + if (NULL != fh) + (void) GNUNET_DISK_file_close (fh); + errno = eno; + return ret; +} + + +/* end of exchangedb_keyio.c */ diff --git a/src/exchangedb/exchangedb_plugin.c b/src/exchangedb/exchangedb_plugin.c new file mode 100644 index 000000000..ebaef9cc0 --- /dev/null +++ b/src/exchangedb/exchangedb_plugin.c @@ -0,0 +1,87 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchangedb/exchangedb_plugin.c + * @brief Logic to load database plugin + * @author Christian Grothoff + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ +#include "platform.h" +#include "taler_exchangedb_plugin.h" +#include <ltdl.h> + + +/** + * Initialize the plugin. + * + * @param cfg configuration to use + * @return #GNUNET_OK on success + */ +struct TALER_EXCHANGEDB_Plugin * +TALER_EXCHANGEDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *plugin_name; + char *lib_name; + struct GNUNET_CONFIGURATION_Handle *cfg_dup; + struct TALER_EXCHANGEDB_Plugin *plugin; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "db", + &plugin_name)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "db"); + return NULL; + } + (void) GNUNET_asprintf (&lib_name, + "libtaler_plugin_exchangedb_%s", + plugin_name); + GNUNET_free (plugin_name); + cfg_dup = GNUNET_CONFIGURATION_dup (cfg); + plugin = GNUNET_PLUGIN_load (lib_name, cfg_dup); + if (NULL != plugin) + plugin->library_name = lib_name; + else + GNUNET_free (lib_name); + GNUNET_CONFIGURATION_destroy (cfg_dup); + return plugin; +} + + +/** + * Shutdown the plugin. + * + * @param plugin the plugin to unload + */ +void +TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin) +{ + char *lib_name; + + if (NULL == plugin) + return; + lib_name = plugin->library_name; + GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, + plugin)); + GNUNET_free (lib_name); +} + + + +/* end of exchangedb_plugin.c */ diff --git a/src/exchangedb/perf_taler_exchangedb.c b/src/exchangedb/perf_taler_exchangedb.c new file mode 100644 index 000000000..6ff7f5331 --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb.c @@ -0,0 +1,358 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/perf_taler_exchangedb.c + * @brief Exchange database performance analysis + * @author Nicolas Fournier + */ +#include "platform.h" +#include "perf_taler_exchangedb_interpreter.h" + + +#define NB_DENOMINATION_INIT 15 +#define NB_DENOMINATION_SAVE 15 + +#define SMALL 1000 +#define BIG 10000 +#define BIGGER 100000 + +#define NB_RESERVE_INIT BIGGER +#define NB_RESERVE_SAVE BIG + +#define NB_DEPOSIT_INIT BIGGER +#define NB_DEPOSIT_SAVE BIG + +#define NB_WITHDRAW_INIT BIGGER +#define NB_WITHDRAW_SAVE BIG + +#define NB_REFRESH_INIT BIGGER +#define NB_REFRESH_SAVE BIG + +#define NB_MELT_INIT BIG +#define NB_MELT_SAVE SMALL + +/** + * Runs the performances tests for the exchange database + * and logs the results using Gauger + */ +int +main (int argc, char ** argv) +{ + int ret; + struct PERF_TALER_EXCHANGEDB_Cmd benchmark[] = + { + /* Denomination used to create coins */ + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("Initializing database"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop", + NB_DENOMINATION_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", + "01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", + "01 - denomination loop", + "01 - denomination", + NB_DENOMINATION_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("01 - end", + "01 - denomination loop"), + /* End of initialization */ + /* Reserve initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop", + NB_RESERVE_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert", + "02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", + "02 - init reserve loop", + "02 - reserve", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("02 - end", + "02 - init reserve loop"), + /* End reserve init */ + /* Withdrawal initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop", + NB_WITHDRAW_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", + "03 - init withdraw loop", + "01 - save denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", + "03 - init withdraw loop", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", + "03 - denomination load", + "03 - reserve load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert", + "03 - withdraw"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - save coin", + "03 - init withdraw loop", + "03 - withdraw", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("03 - end", + "03 - init withdraw loop"), + /*End of withdrawal initialization */ + /*Deposit initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop", + NB_DEPOSIT_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - coin load", + "04 - deposit init loop", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit", + "04 - coin load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert", + "04 - deposit"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", + "04 - deposit init loop", + "04 - deposit", + NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "04 - deposit init loop"), + /* End of deposit initialization */ + /* Session initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("05 - refresh session init loop", + NB_REFRESH_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("05 - session array", + "05 - refresh session init loop", + "05 - refresh session", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("05 - end", + "05 - refresh session init loop"), + /* End of refresh session initialization */ + /* Refresh melt initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("06 - refresh melt init loop", + NB_MELT_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + /* TODO: initialize using coins & sessions created localy + * in order to make sure the same coin are not melted twice*/ + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("06 - session hash", + "06 - refresh melt init loop", + "05 - session array"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("06 - coin", + "06 - refresh melt init loop", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_REFRESH_MELT ("06 - refresh melt", + "06 - session hash", + "06 - coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("06 - end", + "06 - refresh melt init loop"), + /* End of refresh melt initialization */ + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of initialization"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("Start of performances measuring"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("21 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("21 - reserve insert measure", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("21 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("21 - insert", + "21 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "21 - reserve insert measure"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("21 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("21 - gauger", + "21 - start", + "21 - stop", + "POSTGRES", + "Number of reserve inserted per second", + "item/sec", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve insertion"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("22 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("22 - reserve load measure", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("22 - reserve", + "22 - reserve load measure", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE ("22 - get", + "22 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "22 - reserve load measure"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("22 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "22 - start", + "22 - stop", + "POSTGRES", + "Number of reserve loaded per second", + "item/sec", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve retreival"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("23 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("23 - reserve history measure", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("23 - reserve", + "23 - reserve history measure", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY ("", + "23 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "23 - reserve history measure"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("23 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "23 - start", + "23 - stop", + "POSTGRES", + "Number of reserve history loaded per second", + "item/sec", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of reserve history access"), + + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("24 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("24 - withdraw insert measure", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("24 - reserve", + "24 - withdraw insert measure", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("24 - denomination", + "24 - withdraw insert measure", + "01 - save denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("24 - withdraw", + "24 - denomination", + "24 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("24 - insert", + "24 - withdraw"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "24 - withdraw insert measure"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("24 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "24 - start", + "24 - stop", + "POSTGRES", + "Number of withdraw insert per second", + "item/sec", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of withdraw insertion"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("25 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("25 - withdraw insert measure", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("25 - coin", + "25 - withdraw insert measure", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_WITHDRAW ("", + "25 - coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "25 - withdraw insert measure"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("25 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "25 - start", + "25 - stop", + "POSTGRES", + "Number of withdraw loaded per second", + "item/sec", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of withdraw loading"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("26 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("26 - get coin transaction", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("26 - coin", + "26 - get coin transaction", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION("", + "26 - coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "26 - get coin transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("26 - end"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "26 - start", + "26 - end", + "POSTGRES", + "Number of coin transaction history loaded per second", + "item/sec", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of transaction loading"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("27 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("27 - /reserve/withdraw", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("27 - reserve", + "27 - /reserve/withdraw", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("27 - dki", + "27 - /reserve/withdraw", + "01 - save denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_WITHDRAW_SIGN ("", + "27 - dki", + "27 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "27 - /reserve/withdraw"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("27 - end"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "27 - start", + "27 - end", + "POSTGRES", + "Number of /reserve/withdraw per second", + "item/sec", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("End of /reserve/withdraw"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("28 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("28 - /deposit", + NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("28 - coin", + "28 - /deposit", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEPOSIT ("28 - deposit", + "28 - coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "28 - /deposit"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("28 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "28 - start", + "28 - stop", + "POSTGRES", + "Number of /deposit per second", + "item/sec", + NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("29 - start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("29 - insert refresh session", + NB_REFRESH_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "29 - insert refresh session"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("29 - stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("", + "29 - start", + "29 - stop", + "POSTGRES", + "Number of refresh session inserted per second", + "item/sec", + NB_REFRESH_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END (""), + }; + + ret = PERF_TALER_EXCHANGEDB_run_benchmark ( + "perf-taler-exchangedb", + "./test-exchange-db-postgres.conf", + (struct PERF_TALER_EXCHANGEDB_Cmd []) {PERF_TALER_EXCHANGEDB_INIT_CMD_END("")}, + benchmark); + if (GNUNET_SYSERR == ret) + return 1; + return 0; +} diff --git a/src/exchangedb/perf_taler_exchangedb_init.c b/src/exchangedb/perf_taler_exchangedb_init.c new file mode 100644 index 000000000..2e613b3cf --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb_init.c @@ -0,0 +1,622 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/perf_taler_exchangedb_init.c + * @brief Interpreter library for exchange database performance analysis + * @author Nicolas Fournier + */ +#include "platform.h" +#include "perf_taler_exchangedb_init.h" +#include <gnunet/gnunet_signatures.h> +#include "taler_signatures.h" +#include "taler_amount_lib.h" + + +#define CURRENCY "EUR" +#define PERF_TALER_EXCHANGEDB_RSA_SIZE 512 + + +/** + * Generate a dummy DenominationKeyInformation for testing purposes + * @return a dummy denomination key + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +PERF_TALER_EXCHANGEDB_denomination_init () +{ + struct GNUNET_CRYPTO_EddsaPrivateKey *master_prvt; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + struct TALER_DenominationPrivateKey denom_priv; + struct TALER_DenominationPublicKey denom_pub; + struct TALER_EXCHANGEDB_DenominationKeyInformationP issue; + + master_prvt = GNUNET_CRYPTO_eddsa_key_create(); + + dki = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation); + GNUNET_assert (NULL != dki); + denom_priv.rsa_private_key + = GNUNET_CRYPTO_rsa_private_key_create (PERF_TALER_EXCHANGEDB_RSA_SIZE); + GNUNET_assert (NULL != denom_priv.rsa_private_key); + denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key); + GNUNET_assert (NULL != denom_pub.rsa_public_key); + {/* issue */ + struct TALER_MasterSignatureP signature; + struct TALER_DenominationKeyValidityPS properties; + + {/* properties */ + struct TALER_Amount amount; + + properties.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); + properties.purpose.size = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); + GNUNET_CRYPTO_eddsa_key_get_public (master_prvt, + &properties.master.eddsa_pub); + properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get()); + properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); + properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); + properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.1", &amount)); + TALER_amount_hton (&properties.value, &amount); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.1", &amount)); + TALER_amount_hton (&properties.fee_withdraw, &amount); + TALER_amount_hton (&properties.fee_deposit, &amount); + TALER_amount_hton (&properties.fee_refresh, &amount); + GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, + &properties.denom_hash); + issue.properties = properties; + } + {/* signature */ + GNUNET_CRYPTO_eddsa_sign (master_prvt, + &properties.purpose, + &signature.eddsa_signature); + issue.signature = signature; + } + } + dki->denom_priv = denom_priv; + dki->denom_pub = denom_pub; + dki->issue = issue; + GNUNET_free (master_prvt); + return dki; +} + + +/** + * Copies the given denomination + * @param reserve the deposit copy + * @return a copy of @a deposit; NULL if error + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +PERF_TALER_EXCHANGEDB_denomination_copy (const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *copy; + + GNUNET_assert (NULL != + (copy = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation))); + {/* denom_priv */ + copy->denom_priv.rsa_private_key = + GNUNET_CRYPTO_rsa_private_key_dup ( dki->denom_priv.rsa_private_key); + } + {/* denom_pub */ + copy->denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); + } + {/* issue */ + copy->issue.properties = dki->issue.properties; + copy->issue.signature = dki->issue.signature; + } + return copy; +} + + +/** + * Free memory of a DenominationKeyIssueInformation + * @param dki pointer to the struct to free + */ +int +PERF_TALER_EXCHANGEDB_denomination_free (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + if (NULL == dki) + return GNUNET_OK; + GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key); + + GNUNET_free (dki); + return GNUNET_OK; +} + + +/** + * Generate a dummy reserve for testing + * @return a reserve with 1000 EUR in it + */ +struct PERF_TALER_EXCHANGEDB_Reserve * +PERF_TALER_EXCHANGEDB_reserve_init () +{ + struct PERF_TALER_EXCHANGEDB_Reserve *reserve; + + GNUNET_assert (NULL != + (reserve = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Reserve))); + {/* private */ + struct GNUNET_CRYPTO_EddsaPrivateKey *private; + private = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_assert (NULL != private); + reserve->private = *private; + GNUNET_free (private); + } + + GNUNET_CRYPTO_eddsa_key_get_public (&reserve->private, + &reserve->reserve.pub.eddsa_pub); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1000", &reserve->reserve.balance)); + reserve->reserve.expiry = GNUNET_TIME_absolute_get_forever_ (); + return reserve; +} + + +/** + * Copies the given reserve + * @param reserve the reserve to copy + * @return a copy of @a reserve; NULL if error + */ +struct PERF_TALER_EXCHANGEDB_Reserve * +PERF_TALER_EXCHANGEDB_reserve_copy (const struct PERF_TALER_EXCHANGEDB_Reserve *reserve) +{ + struct PERF_TALER_EXCHANGEDB_Reserve *copy; + GNUNET_assert (NULL != + (copy = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Reserve))); + *copy = *reserve; + return copy; +} + + +/** + * Free memory of a reserve + * @param reserve pointer to the structure to be freed + */ +int +PERF_TALER_EXCHANGEDB_reserve_free (struct PERF_TALER_EXCHANGEDB_Reserve *reserve) +{ + if (NULL == reserve) + return GNUNET_OK; + GNUNET_free (reserve); + return GNUNET_OK; +} + + +/** + * Generate a dummy deposit for testing purposes + * @param dki the denomination key used to sign the key + */ +struct TALER_EXCHANGEDB_Deposit * +PERF_TALER_EXCHANGEDB_deposit_init (const struct PERF_TALER_EXCHANGEDB_Coin *coin) +{ + struct TALER_EXCHANGEDB_Deposit *deposit; + struct TALER_CoinSpendSignatureP csig; + struct TALER_MerchantPublicKeyP merchant_pub; + struct GNUNET_HashCode h_contract; + struct GNUNET_HashCode h_wire; + const char wire[] = "{" + "\"type\":\"SEPA\"," + "\"IBAN\":\"DE67830654080004822650\"," + "\"NAME\":\"GNUNET E.\"," + "\"BIC\":\"GENODEF1SRL\"" + "}"; + static uint64_t transaction_id = 0; + struct GNUNET_TIME_Absolute timestamp; + struct GNUNET_TIME_Absolute refund_deadline; + struct TALER_Amount amount_with_fee; + struct TALER_Amount deposit_fee; + + GNUNET_assert (NULL != + (deposit = GNUNET_malloc (sizeof (struct TALER_EXCHANGEDB_Deposit) + sizeof (wire)))); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &h_contract); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &h_wire); + { //csig + struct u32_presign + { + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_wire; + struct GNUNET_HashCode h_contract; + } unsigned_data; + + unsigned_data.h_contract = h_contract; + unsigned_data.h_wire = h_wire; + unsigned_data.purpose.size = htonl (sizeof (struct u32_presign)); + unsigned_data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&coin->priv, + &unsigned_data.purpose, + &csig.eddsa_signature)); + } + { //merchant_pub + struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_prv; + + eddsa_prv = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_assert(NULL != eddsa_prv); + GNUNET_CRYPTO_eddsa_key_get_public ( + eddsa_prv, + &merchant_pub.eddsa_pub); + GNUNET_free (eddsa_prv); + } + timestamp = GNUNET_TIME_absolute_get (); + refund_deadline = GNUNET_TIME_absolute_get (); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.1", + &amount_with_fee)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.1", + &deposit_fee)); + { + deposit->coin.coin_pub = coin->public_info.coin_pub; + deposit->coin.denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup ( + coin->public_info.denom_pub.rsa_public_key); + GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key); + deposit->coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup ( + coin->public_info.denom_sig.rsa_signature); + GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature); + } + deposit->csig = csig; + deposit->h_contract = h_contract; + deposit->h_wire = h_wire; + deposit->wire = json_loads (wire, 0, NULL); + deposit->transaction_id = transaction_id++; + deposit->timestamp = timestamp; + deposit->refund_deadline = refund_deadline; + deposit->amount_with_fee = amount_with_fee; + deposit->deposit_fee = deposit_fee; + return deposit; +} + + +/** + * Copies the given deposit + * @param reserve the deposit copy + * @return a copy of @a deposit; NULL if error + */ +struct TALER_EXCHANGEDB_Deposit * +PERF_TALER_EXCHANGEDB_deposit_copy (const struct TALER_EXCHANGEDB_Deposit *deposit) +{ + struct TALER_EXCHANGEDB_Deposit *copy; + + copy = GNUNET_new (struct TALER_EXCHANGEDB_Deposit); + *copy = *deposit; + json_incref (copy->wire); + copy->coin.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key); + copy->coin.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (deposit->coin.denom_sig.rsa_signature); + return copy; +} + + +/** + * Free memory of a deposit + * @param deposit pointer to the structure to free + */ +int +PERF_TALER_EXCHANGEDB_deposit_free (struct TALER_EXCHANGEDB_Deposit *deposit) +{ + if (NULL == deposit) + return GNUNET_OK; + GNUNET_CRYPTO_rsa_public_key_free (deposit->coin.denom_pub.rsa_public_key); + GNUNET_CRYPTO_rsa_signature_free (deposit->coin.denom_sig.rsa_signature); + json_decref (deposit->wire); + GNUNET_free (deposit); + return GNUNET_OK; +} + + +/** + * Generate a CollectableBlindcoin for testing purpuses + * @param dki denomination key used to sign the coin + * @param reserve reserve providing the money for the coin + * @return a randomly generated CollectableBlindcoin + */ +struct PERF_TALER_EXCHANGEDB_Coin * +PERF_TALER_EXCHANGEDB_coin_init ( + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, + const struct PERF_TALER_EXCHANGEDB_Reserve *reserve) +{ + struct PERF_TALER_EXCHANGEDB_Coin *coin; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + coin = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Coin); + GNUNET_assert (NULL != coin); + /* priv */ + + priv = GNUNET_CRYPTO_eddsa_key_create(); + GNUNET_assert (NULL != priv); + coin->priv = *priv; + GNUNET_free (priv); + + /* public_info */ + GNUNET_CRYPTO_eddsa_key_get_public (&coin->priv, + &coin->public_info.coin_pub.eddsa_pub); + coin->public_info.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); + coin->public_info.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, + &coin->public_info.coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)); + GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key); + GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature); + + /* blind */ + coin->blind.sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); + coin->blind.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); + GNUNET_assert (NULL != coin->blind.sig.rsa_signature); + GNUNET_assert (NULL != coin->blind.denom_pub.rsa_public_key); + TALER_amount_ntoh (&coin->blind.amount_with_fee, + &dki->issue.properties.value); + TALER_amount_ntoh (&coin->blind.withdraw_fee, + &dki->issue.properties.fee_withdraw); + coin->blind.reserve_pub = reserve->reserve.pub; + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &coin->blind.h_coin_envelope); + + return coin; +} + + +/** + * Copies the given coin + * + * @param coin the coin to copy + * @return a copy of coin; NULL if error + */ +struct PERF_TALER_EXCHANGEDB_Coin * +PERF_TALER_EXCHANGEDB_coin_copy (const struct PERF_TALER_EXCHANGEDB_Coin *coin) +{ + struct PERF_TALER_EXCHANGEDB_Coin *copy; + + copy = GNUNET_new (struct PERF_TALER_EXCHANGEDB_Coin); + /* priv */ + copy->priv = coin->priv; + /* public_info */ + copy->public_info.coin_pub = coin->public_info.coin_pub; + copy->public_info.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key); + copy->public_info.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); + + /* blind */ + copy->blind.sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (coin->blind.sig.rsa_signature); + copy->blind.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (coin->blind.denom_pub.rsa_public_key); + copy->blind.amount_with_fee = coin->blind.amount_with_fee; + copy->blind.withdraw_fee = coin->blind.withdraw_fee; + copy->blind.reserve_pub = coin->blind.reserve_pub; + copy->blind.h_coin_envelope = coin->blind.h_coin_envelope; + copy->blind.reserve_sig = coin->blind.reserve_sig; + + return copy; +} + + +/** + * Free memory of @a coin + * + * @param coin pointer to the structure to free + */ +int +PERF_TALER_EXCHANGEDB_coin_free (struct PERF_TALER_EXCHANGEDB_Coin *coin) +{ + if (NULL == coin) + return GNUNET_OK; + GNUNET_CRYPTO_rsa_public_key_free (coin->public_info.denom_pub.rsa_public_key); + GNUNET_CRYPTO_rsa_signature_free (coin->public_info.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_signature_free (coin->blind.sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (coin->blind.denom_pub.rsa_public_key); + GNUNET_free (coin); + return GNUNET_OK; +} + + +/** + * @return a randomly generated refresh session + */ +struct TALER_EXCHANGEDB_RefreshSession * +PERF_TALER_EXCHANGEDB_refresh_session_init () +{ + struct TALER_EXCHANGEDB_RefreshSession *refresh_session; + + GNUNET_assert (NULL != + (refresh_session = GNUNET_new (struct TALER_EXCHANGEDB_RefreshSession))); + refresh_session->noreveal_index = 1; + refresh_session->num_oldcoins = 1; + refresh_session->num_newcoins = 1; + + return refresh_session; +} + + +/** + * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't + */ +int +PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session, + struct TALER_EXCHANGEDB_RefreshSession *copy) +{ + *copy = *session; + return GNUNET_OK; +} + + +/** + * Free a refresh session + */ +int +PERF_TALER_EXCHANGEDB_refresh_session_free (struct TALER_EXCHANGEDB_RefreshSession *refresh_session) +{ + if (NULL == refresh_session) + return GNUNET_OK; + GNUNET_free (refresh_session); + return GNUNET_OK; +} + + +/** + * Create a melt operation + * + * @param session the refresh session + * @param dki the denomination the melted coin uses + * @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt + */ +struct TALER_EXCHANGEDB_RefreshMelt * +PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session, + struct PERF_TALER_EXCHANGEDB_Coin *coin) +{ + struct TALER_EXCHANGEDB_RefreshMelt *melt; + struct TALER_CoinSpendSignatureP coin_sig; + struct TALER_Amount amount; + struct TALER_Amount amount_with_fee; + + { + struct + { + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode session; + } to_sign; + + to_sign.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_TEST; + to_sign.purpose.size = htonl (sizeof (to_sign)); + to_sign.session = *session; + GNUNET_CRYPTO_eddsa_sign (&coin->priv, + &to_sign.purpose, + &coin_sig.eddsa_signature); + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.1", + &amount)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.1", + &amount_with_fee)); + melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt); + melt->coin.coin_pub = coin->public_info.coin_pub; + melt->coin.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); + melt->coin.denom_pub.rsa_public_key = + GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key); + GNUNET_assert (NULL != melt->coin.denom_pub.rsa_public_key); + GNUNET_assert (NULL != melt->coin.denom_sig.rsa_signature); + melt->coin_sig = coin_sig; + melt->session_hash = *session; + melt->amount_with_fee = amount; + melt->melt_fee = amount_with_fee; + return melt; +} + + +/** + * Copies the internals of a #TALER_EXCHANGEDB_RefreshMelt + * + * @param melt the refresh melt to copy + * @return an copy of @ melt + */ +struct TALER_EXCHANGEDB_RefreshMelt * +PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMelt *melt) +{ + struct TALER_EXCHANGEDB_RefreshMelt *copy; + + copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt); + *copy = *melt; + copy->coin.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_signature_dup (melt->coin.denom_sig.rsa_signature); + GNUNET_assert (NULL != copy->coin.denom_sig.rsa_signature); + + return copy; +} + + +/** + * Free the internal memory of a #TALER_EXCHANGEDB_RefreshMelt + * + * @param melt the #TALER_EXCHANGEDB_RefreshMelt to free + * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR + */ +int +PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt) +{ + GNUNET_CRYPTO_rsa_signature_free (melt->coin.denom_sig.rsa_signature); + GNUNET_free (melt); + return GNUNET_OK; +} + + +/** + * Create a #TALER_EXCHANGEDB_RefreshCommitCoin + */ +struct TALER_EXCHANGEDB_RefreshCommitCoin * +PERF_TALER_EXCHANGEDB_refresh_commit_coin_init () +{ + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin; + struct TALER_RefreshLinkEncrypted refresh_link; + + commit_coin = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin); + GNUNET_assert (NULL != commit_coin); + {/* refresh_link */ + refresh_link = (struct TALER_RefreshLinkEncrypted) + { + .blinding_key_enc = "blinding_key", + .blinding_key_enc_size = 13 + }; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &refresh_link.coin_priv_enc, + sizeof(struct TALER_CoinSpendPrivateKeyP)); + } + commit_coin->coin_ev = "coin_ev"; + commit_coin->coin_ev_size = 8; + commit_coin->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted); + *commit_coin->refresh_link = refresh_link; + return commit_coin; +} + + +/** + * Copies a #TALER_EXCHANGEDB_RefreshCommitCoin + * + * @param commit_coin the commit to copy + * @return a copy of @a commit_coin + */ +struct TALER_EXCHANGEDB_RefreshCommitCoin * +PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin) +{ + struct TALER_EXCHANGEDB_RefreshCommitCoin *copy; + + copy = GNUNET_new (struct TALER_EXCHANGEDB_RefreshCommitCoin); + copy->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted); + *copy->refresh_link = *commit_coin->refresh_link; + return copy; +} + + +/** + * Free a #TALER_EXCHANGEDB_RefreshCommitCoin + * + * @param commit_coin the coin to free + */ +void +PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin) +{ + GNUNET_free (commit_coin->refresh_link); + GNUNET_free (commit_coin); +} diff --git a/src/exchangedb/perf_taler_exchangedb_init.h b/src/exchangedb/perf_taler_exchangedb_init.h new file mode 100644 index 000000000..0ff074108 --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb_init.h @@ -0,0 +1,257 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/perf_taler_exchangedb_init.h + * @brief Heler function for creating dummy inputs for the exchange database + * @author Nicolas Fournier + */ +#ifndef __PERF_TALER_EXCHANGEDB_INIT_H___ +#define __PERF_TALER_EXCHANGEDB_INIT_H___ + +#include "taler_exchangedb_plugin.h" + + +#define CURRENCY "EUR" + +/** + * All information about a reserve + */ +struct PERF_TALER_EXCHANGEDB_Reserve +{ + /** + * Information about a rserve available to the Exchange + */ + struct TALER_EXCHANGEDB_Reserve reserve; + + /** + * Private key of a reserve + */ + struct GNUNET_CRYPTO_EddsaPrivateKey private; +}; + + +/** + * All informations about a coin + */ +struct PERF_TALER_EXCHANGEDB_Coin +{ + /** + * Blinded coin, known by the exchange + */ + struct TALER_EXCHANGEDB_CollectableBlindcoin blind; + + /** + * Public key of the coin and othes informations + */ + struct TALER_CoinPublicInfo public_info; + + /** + * Private key of the coin + */ + struct GNUNET_CRYPTO_EddsaPrivateKey priv; +}; + + +/** + * Generate a dummy DenominationKeyInformation for testing purposes + * @return a dummy denomination key + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +PERF_TALER_EXCHANGEDB_denomination_init (void); + + +/** + * Copies the given denomination + * @param reserve the deposit copy + * @return a copy of @a deposit; NULL if error + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation * +PERF_TALER_EXCHANGEDB_denomination_copy ( + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + + +/** + * Free memory of a DenominationKeyIssueInformation + * @param dki pointer to the struct to free + */ +int +PERF_TALER_EXCHANGEDB_denomination_free ( + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + + +/** + * Generate a dummy reserve for testing + * @return a reserve with 1000 EUR in it + */ +struct PERF_TALER_EXCHANGEDB_Reserve * +PERF_TALER_EXCHANGEDB_reserve_init (void); + + +/** + * Copies the given reserve + * @param reserve the reserve to copy + * @return a copy of @a reserve; NULL if error + */ +struct PERF_TALER_EXCHANGEDB_Reserve * +PERF_TALER_EXCHANGEDB_reserve_copy (const struct PERF_TALER_EXCHANGEDB_Reserve *reserve); + + +/** + * Free memory of a reserve + * @param reserve pointer to the structure to be freed + */ +int +PERF_TALER_EXCHANGEDB_reserve_free (struct PERF_TALER_EXCHANGEDB_Reserve *reserve); + + +/** + * Generate a dummy deposit for testing purposes + * @param dki the denomination key used to sign the key + */ +struct TALER_EXCHANGEDB_Deposit * +PERF_TALER_EXCHANGEDB_deposit_init ( + const struct PERF_TALER_EXCHANGEDB_Coin *coin); + + +/** + * Copies the given deposit + * @param reserve the deposit copy + * @return a copy of @a deposit; NULL if error + */ +struct TALER_EXCHANGEDB_Deposit * +PERF_TALER_EXCHANGEDB_deposit_copy (const struct TALER_EXCHANGEDB_Deposit *deposit); + + +/** + * Free memory of a deposit + * @param deposit pointer to the structure to free + */ +int +PERF_TALER_EXCHANGEDB_deposit_free (struct TALER_EXCHANGEDB_Deposit *deposit); + + +/** + * Generate a coin for testing purpuses + * @param dki denomination key used to sign the coin + * @param reserve reserve providing the money for the coin + * @return a randomly generated CollectableBlindcoin + */ +struct PERF_TALER_EXCHANGEDB_Coin * +PERF_TALER_EXCHANGEDB_coin_init ( + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, + const struct PERF_TALER_EXCHANGEDB_Reserve *reserve); + + +/** + * Copies the given coin + * @param coin the coin to copy + * @return a copy of coin; NULL if error + */ +struct PERF_TALER_EXCHANGEDB_Coin * +PERF_TALER_EXCHANGEDB_coin_copy ( + const struct PERF_TALER_EXCHANGEDB_Coin *coin); + + +/** + * Liberate memory of @a coin + * @param coin pointer to the structure to free + */ +int +PERF_TALER_EXCHANGEDB_coin_free ( + struct PERF_TALER_EXCHANGEDB_Coin *coin); + + +/** + * @return a randomly generated refresh session + */ +struct TALER_EXCHANGEDB_RefreshSession * +PERF_TALER_EXCHANGEDB_refresh_session_init (void); + + +/** + * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't + */ +int +PERF_TALER_EXCHANGEDB_refresh_session_copy (struct TALER_EXCHANGEDB_RefreshSession *session, + struct TALER_EXCHANGEDB_RefreshSession *copy); + + +/** + * Frees memory of a refresh_session + */ +int +PERF_TALER_EXCHANGEDB_refresh_session_free ( + struct TALER_EXCHANGEDB_RefreshSession *refresh_session); + + +/** + * Create a melt operation + * + * @param session the refresh session + * @param dki the denomination the melted coin uses + * @return a pointer to a #TALER_EXCHANGEDB_RefreshMelt + */ +struct TALER_EXCHANGEDB_RefreshMelt * +PERF_TALER_EXCHANGEDB_refresh_melt_init (struct GNUNET_HashCode *session, + struct PERF_TALER_EXCHANGEDB_Coin *coin); + + +/** + * Copies the internals of a #TALER_EXCHANGEDB_RefreshMelt + * + * @param melt the refresh melt to copy + * @return an copy of @ melt + */ +struct TALER_EXCHANGEDB_RefreshMelt * +PERF_TALER_EXCHANGEDB_refresh_melt_copy (const struct TALER_EXCHANGEDB_RefreshMelt *melt); + + +/** + * Free the internal memory of a #TALER_EXCHANGEDB_RefreshMelt + * + * @param melt the #TALER_EXCHANGEDB_RefreshMelt to free + * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR + */ +int +PERF_TALER_EXCHANGEDB_refresh_melt_free (struct TALER_EXCHANGEDB_RefreshMelt *melt); + + +/** + * Create a #TALER_EXCHANGEDB_RefreshCommitCoin + */ +struct TALER_EXCHANGEDB_RefreshCommitCoin * +PERF_TALER_EXCHANGEDB_refresh_commit_coin_init (void); + + +/** + * Copies a #TALER_EXCHANGEDB_RefreshCommitCoin + * + * @param commit_coin the commit to copy + * @return a copy of @a commit_coin + */ +struct TALER_EXCHANGEDB_RefreshCommitCoin * +PERF_TALER_EXCHANGEDB_refresh_commit_coin_copy (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin); + + +/** + * Free a #TALER_EXCHANGEDB_RefreshCommitCoin + * + * @param commit_coin the coin to free + */ +void +PERF_TALER_EXCHANGEDB_refresh_commit_coin_free (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin); + +#endif diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c new file mode 100644 index 000000000..75b32cb60 --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c @@ -0,0 +1,1998 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/perf_taler_exchangedb_interpreter.c + * @brief Interpreter library for exchange database performance analysis + * @author Nicolas Fournier + */ +#include "platform.h" +#include "perf_taler_exchangedb_interpreter.h" +#include "perf_taler_exchangedb_init.h" +#include "gauger.h" + + +/** + * Represents the state of the interpreter + */ +struct PERF_TALER_EXCHANGEDB_interpreter_state +{ + /** + * State of the commands + */ + struct PERF_TALER_EXCHANGEDB_Cmd *cmd; + + /** + * Database plugin + */ + struct TALER_EXCHANGEDB_Plugin *plugin; + + /** + * Current database session + */ + struct TALER_EXCHANGEDB_Session *session; + + /** + * The current index of the interpreter + */ + unsigned int i; +}; + + +/** + * Free the memory of @a data + */ +static void +data_free (struct PERF_TALER_EXCHANGEDB_Data *data) +{ + switch (data->type) + { + case PERF_TALER_EXCHANGEDB_TIME: + if (NULL == data->data.time) + break; + GNUNET_free (data->data.time); + data->data.time = NULL; + break; + + case PERF_TALER_EXCHANGEDB_DEPOSIT: + if (NULL == data->data.deposit) + break; + PERF_TALER_EXCHANGEDB_deposit_free (data->data.deposit); + data->data.deposit = NULL; + break; + + case PERF_TALER_EXCHANGEDB_COIN: + if (NULL == data->data.coin) + break; + PERF_TALER_EXCHANGEDB_coin_free (data->data.coin); + data->data.coin = NULL; + break; + + case PERF_TALER_EXCHANGEDB_RESERVE: + if (NULL == data->data.reserve) + break; + PERF_TALER_EXCHANGEDB_reserve_free (data->data.reserve); + data->data.reserve = NULL; + break; + + case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO: + if (NULL == data->data.dki) + break; + PERF_TALER_EXCHANGEDB_denomination_free (data->data.dki); + data->data.dki = NULL; + break; + + case PERF_TALER_EXCHANGEDB_REFRESH_HASH: + if (NULL == data->data.session_hash) + break; + GNUNET_free (data->data.session_hash); + data->data.session_hash = NULL; + break; + + case PERF_TALER_EXCHANGEDB_REFRESH_MELT: + if (NULL == data->data.refresh_melt) + break; + PERF_TALER_EXCHANGEDB_refresh_melt_free (data->data.refresh_melt); + data->data.refresh_melt = NULL; + break; + + case PERF_TALER_EXCHANGEDB_NONE: + break; + } +} + + +/** + * Copies @a data into @a copy + * + * @param data the data to be copied + * @param[out] copy the copy made + */ +static void +data_copy (const struct PERF_TALER_EXCHANGEDB_Data *data, + struct PERF_TALER_EXCHANGEDB_Data *copy) +{ + copy->type = data->type; + switch (data->type) + { + case PERF_TALER_EXCHANGEDB_TIME: + copy->data.time = GNUNET_new (struct GNUNET_TIME_Absolute); + *copy->data.time = *data->data.time; + return; + + case PERF_TALER_EXCHANGEDB_DEPOSIT: + copy->data.deposit + = PERF_TALER_EXCHANGEDB_deposit_copy (data->data.deposit); + return; + + case PERF_TALER_EXCHANGEDB_COIN: + copy->data.coin + = PERF_TALER_EXCHANGEDB_coin_copy (data->data.coin); + return; + + case PERF_TALER_EXCHANGEDB_RESERVE: + copy->data.reserve + = PERF_TALER_EXCHANGEDB_reserve_copy (data->data.reserve); + return; + + case PERF_TALER_EXCHANGEDB_DENOMINATION_INFO: + copy->data.dki + = PERF_TALER_EXCHANGEDB_denomination_copy (data->data.dki); + return; + + case PERF_TALER_EXCHANGEDB_REFRESH_HASH: + copy-> data.session_hash = GNUNET_new (struct GNUNET_HashCode); + *copy->data.session_hash + = *data->data.session_hash; + break; + + case PERF_TALER_EXCHANGEDB_REFRESH_MELT: + copy->data.refresh_melt + = PERF_TALER_EXCHANGEDB_refresh_melt_copy (data->data.refresh_melt); + break; + + case PERF_TALER_EXCHANGEDB_NONE: + break; + } +} + + +/** + * Finds the first command in cmd with the name search + * + * @return the index of the first command with name search + * #GNUNET_SYSERR if none found + */ +static int +cmd_find (const struct PERF_TALER_EXCHANGEDB_Cmd *cmd, + const char *search) +{ + unsigned int i; + + for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++) + if (0 == strcmp (cmd[i].label, search)) + return i; + return GNUNET_SYSERR; +} + + +/** + * Initialization of a command array + * and check for the type of the label + * + * @param cmd the comand array initialized + * @return #GNUNET_OK if the initialization was sucessful + * #GNUNET_SYSERR if there was a probleb. See the log for details + */ +static int +cmd_init (struct PERF_TALER_EXCHANGEDB_Cmd cmd[]) +{ + unsigned int i; + + for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++) + { + switch (cmd[i].command) + { + case PERF_TALER_EXCHANGEDB_CMD_END_LOOP: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.end_loop.label_loop); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.end_loop.label_loop); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.end_loop.label_loop); + return GNUNET_SYSERR; + } + cmd[i].details.end_loop.index_loop = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.save_array.label_save); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.save_array.label_save); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_NONE == cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.save_array.label_save); + return GNUNET_SYSERR; + } + cmd[i].details.save_array.index_save = ret; + + ret = cmd_find (cmd, + cmd[i].details.save_array.label_loop); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.save_array.label_loop); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.save_array.label_loop); + return GNUNET_SYSERR; + } + cmd[i].details.save_array.index_loop = ret; + + GNUNET_assert (NULL == cmd[i].details.save_array.data_saved); + cmd[i].details.save_array.data_saved = + GNUNET_new_array (cmd[i].details.save_array.nb_saved, + struct PERF_TALER_EXCHANGEDB_Data); + cmd[i].details.save_array.type_saved = + cmd[cmd[i].details.save_array.index_save].exposed.type; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.load_array.label_save); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.load_array.label_save); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY != cmd[ret].command) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.load_array.label_save); + return GNUNET_SYSERR; + } + cmd[i].details.load_array.index_save = ret; + + ret = cmd_find (cmd, + cmd[i].details.load_array.label_loop); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.load_array.label_loop); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_CMD_LOOP != cmd[ret].command) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.load_array.label_loop); + return GNUNET_SYSERR; + } + cmd[i].details.load_array.index_loop = ret; + + cmd[i].details.load_array.permutation = + GNUNET_CRYPTO_random_permute ( + GNUNET_CRYPTO_QUALITY_WEAK, + cmd[cmd[i].details.load_array.index_save].details.save_array.nb_saved); + GNUNET_assert (NULL != cmd[i].details.load_array.permutation); + + cmd[i].exposed.type = cmd[cmd[i].details.load_array.index_save].details.save_array.type_saved; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.load_random.label_save); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.load_random.label_save); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY != cmd[ret].command) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.load_random.label_save); + return GNUNET_SYSERR; + } + cmd[i].details.load_random.index_save = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GAUGER: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.gauger.label_start); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.gauger.label_start); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_TIME != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.gauger.label_start); + return GNUNET_SYSERR; + } + cmd[i].details.gauger.index_start = ret; + + ret = cmd_find (cmd, + cmd[i].details.gauger.label_stop); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.gauger.label_stop); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_TIME != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.gauger.label_stop); + return GNUNET_SYSERR; + } + cmd[i].details.gauger.index_stop = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.insert_denomination.label_denom); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_denomination.label_denom); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_denomination.label_denom); + return GNUNET_SYSERR; + } + cmd[i].details.insert_denomination.index_denom = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_denomination.label_denom); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_denomination.label_denom); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_denomination.label_denom); + return GNUNET_SYSERR; + } + cmd[i].details.get_denomination.index_denom = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.insert_reserve.label_reserve); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_reserve.label_reserve); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_reserve.label_reserve); + return GNUNET_SYSERR; + } + cmd[i].details.insert_reserve.index_reserve = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_reserve.label_reserve); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_reserve.label_reserve); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_reserve.label_reserve); + return GNUNET_SYSERR; + } + cmd[i].details.get_reserve.index_reserve = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_reserve_history.label_reserve); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_reserve_history.label_reserve); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_reserve_history.label_reserve); + return GNUNET_SYSERR; + } + cmd[i].details.get_reserve_history.index_reserve = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.create_withdraw.label_dki); + { + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.create_withdraw.label_dki); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.create_withdraw.label_dki); + return GNUNET_SYSERR; + } + } + cmd[i].details.create_withdraw.index_dki = ret; + ret = cmd_find (cmd, + cmd[i].details.create_withdraw.label_reserve); + { + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.create_withdraw.label_reserve); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_RESERVE != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.create_withdraw.label_reserve); + return GNUNET_SYSERR; + } + } + cmd[i].details.create_withdraw.index_reserve = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.insert_withdraw.label_coin); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_withdraw.label_coin); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_withdraw.label_coin); + return GNUNET_SYSERR; + } + cmd[i].details.insert_withdraw.index_coin = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_withdraw.label_coin); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_withdraw.label_coin); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_withdraw.label_coin); + return GNUNET_SYSERR; + } + cmd[i].details.get_withdraw.index_coin = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_coin_transaction.label_coin); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_coin_transaction.label_coin); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_coin_transaction.label_coin); + return GNUNET_SYSERR; + } + cmd[i].details.get_coin_transaction.index_coin = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.create_deposit.label_coin); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.create_deposit.label_coin); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.create_deposit.label_coin); + return GNUNET_SYSERR; + } + cmd[i].details.create_deposit.index_coin = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT: + { + int ret; + + ret = cmd_find( cmd, + cmd[i].details.insert_deposit.label_deposit); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_deposit.label_deposit); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DEPOSIT != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_deposit.label_deposit); + return GNUNET_SYSERR; + } + cmd[i].details.insert_deposit.index_deposit = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_deposit.label_deposit); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_deposit.label_deposit); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DEPOSIT != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_deposit.label_deposit); + return GNUNET_SYSERR; + } + cmd[i].details.get_deposit.index_deposit = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.get_refresh_session.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_refresh_session.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_refresh_session.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_refresh_session.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT: + { + int ret; + + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_melt.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_melt.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_melt.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_melt.index_hash = ret; + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_melt.label_coin); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_melt.label_coin); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_COIN != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_melt.label_coin); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_melt.index_coin = ret; } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_refresh_melt.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_refresh_melt.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_refresh_melt.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_refresh_melt.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_order.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_order.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_order.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_order.index_hash = ret; + + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_order.label_denom); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_order.label_denom); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_DENOMINATION_INFO != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_order.label_denom); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_order.index_denom = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_refresh_order.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_refresh_order.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_refresh_order.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_refresh_order.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_commit_coin.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_commit_coin.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_commit_coin.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_commit_coin.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_refresh_commit_coin.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_refresh_commit_coin.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_refresh_commit_coin.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_refresh_commit_coin.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_commit_link.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_commit_link.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_commit_link.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_commit_link.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_refresh_commit_link.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_refresh_commit_link.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_refresh_commit_link.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_refresh_commit_link.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_melt_commitment.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_melt_commitment.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_melt_commitment.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_melt_commitment.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.insert_refresh_out.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.insert_refresh_out.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.insert_refresh_out.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.insert_refresh_out.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_link_data_list.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_link_data_list.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_link_data_list.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_link_data_list.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER: + { + int ret; + ret = cmd_find (cmd, + cmd[i].details.get_transfer.label_hash); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Undefined reference to %s\n", + i, + cmd[i].details.get_transfer.label_hash); + return GNUNET_SYSERR; + } + if (PERF_TALER_EXCHANGEDB_REFRESH_HASH != cmd[ret].exposed.type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%d:Wrong type reference to %s\n", + i, + cmd[i].details.get_transfer.label_hash); + return GNUNET_SYSERR; + } + cmd[i].details.get_transfer.index_hash = ret; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_END: + case PERF_TALER_EXCHANGEDB_CMD_DEBUG: + case PERF_TALER_EXCHANGEDB_CMD_LOOP: + case PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION: + case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION: + case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION: + case PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION: + case PERF_TALER_EXCHANGEDB_CMD_GET_TIME: + case PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION: + case PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE: + case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION: + break; + } + } + return GNUNET_OK; +} + + +/** + * Free the memory of the command chain + */ +static int +cmd_clean (struct PERF_TALER_EXCHANGEDB_Cmd cmd[]) +{ + unsigned int i; + + for (i=0; PERF_TALER_EXCHANGEDB_CMD_END != cmd[i].command; i++) + { + switch (cmd[i].command) + { + case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY: + { + unsigned int j; + + for (j = 0; j < cmd[i].details.save_array.nb_saved; j++) + { + data_free (&cmd[i].details.save_array.data_saved[j]); + } + GNUNET_free (cmd[i].details.save_array.data_saved); + cmd[i].details.save_array.data_saved = NULL; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY: + GNUNET_free (cmd[i].details.load_array.permutation); + cmd[i].details.load_array.permutation = NULL; + break; + + default: + break; + } + data_free (&cmd[i].exposed); + } + return GNUNET_OK; +} + + +/** + * Handles the command #PERF_TALER_EXCHANGEDB_CMD_END_LOOP for the interpreter + * Cleans the memory at the end of the loop + */ +static void +interpret_end_loop (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) +{ + unsigned int i; + int jump; + + jump = state->cmd[state->i].details.end_loop.index_loop; + // Cleaning up the memory in the loop + for (i = jump; i < state->i; i++) + data_free (&state->cmd[i].exposed); + + state->cmd[jump].details.loop.curr_iteration++; + /* If the loop is not finished */ + if (state->cmd[jump].details.loop.max_iterations > + state->cmd[jump].details.loop.curr_iteration) + { + /* jump back to the start */ + state->i = jump; + } + else + { + /* Reset the loop counter and continue running */ + state->cmd[jump].details.loop.curr_iteration = 0; + } +} + + +/** + * Part of the interpreter specific to + * #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY + * Saves the data exposed by another command into + * an array in the command specific struct. + */ +static void +interpret_save_array (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) +{ + struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i]; + struct PERF_TALER_EXCHANGEDB_Cmd *save_ref; + struct PERF_TALER_EXCHANGEDB_Cmd *loop_ref; + int loop_index; + int save_index; + unsigned int selection_chance; + + loop_index = cmd->details.save_array.index_loop; + save_index = cmd->details.save_array.index_save; + loop_ref = &state->cmd[loop_index]; + save_ref = &state->cmd[save_index]; + /* Array initialization on first loop iteration + Alows for nested loops */ + if (0 == cmd->details.loop.curr_iteration) + { + cmd->details.save_array.index = 0; + } + /* The probability distribution of the saved items will be a little biased + against the few last items but it should not be a big problem. */ + selection_chance = loop_ref->details.loop.max_iterations / + cmd->details.save_array.nb_saved; + /* + * If the remaining space is equal to the remaining number of + * iterations, the item is automaticly saved. + * + * Else it is saved only if the random numbre generated is 0 + */ + if ( (0 < (cmd->details.save_array.nb_saved - + cmd->details.save_array.index) ) && + ( ((loop_ref->details.loop.max_iterations - + loop_ref->details.loop.curr_iteration) == + (cmd->details.save_array.nb_saved - + cmd->details.save_array.index)) || + (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + selection_chance)) ) ) + { + struct PERF_TALER_EXCHANGEDB_Data *save_location; + struct PERF_TALER_EXCHANGEDB_Data *item_saved; + + save_location = &cmd->details.save_array.data_saved[cmd->details.save_array.index]; + item_saved = &save_ref->exposed; + data_copy (item_saved, save_location); + cmd->details.save_array.index++; + } +} + + +/** + * Part of the interpreter specific to + * #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY + * Gets data from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY and exposes a copy + */ +static void +interpret_load_array (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) +{ + struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i]; + unsigned int loop_iter; + int loop_index; + int save_index; + struct PERF_TALER_EXCHANGEDB_Data *loaded_data; + + loop_index = cmd->details.load_array.index_loop; + save_index = cmd->details.load_array.index_save; + loop_iter = state->cmd[loop_index].details.loop.curr_iteration; + { + unsigned int i; + unsigned int quotient; + + /* In case the iteration number is higher than the amount saved, + * the number is run several times in the permutation array */ + quotient = loop_iter / state->cmd[save_index].details.save_array.nb_saved; + loop_iter = loop_iter % state->cmd[save_index].details.save_array.nb_saved; + for (i=0; i<=quotient; i++) + loop_iter = cmd->details.load_array.permutation[loop_iter]; + } + /* Extracting the data from the loop_indexth indice in save_index + * array. + */ + loaded_data = &state->cmd[save_index].details.save_array.data_saved[loop_iter]; + data_copy (loaded_data, + &cmd->exposed); +} + + +/** + * Part of the interpreter specific to + * #PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM + * Get a random element from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY and exposes it + */ +static void +interprete_load_random (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) +{ + struct PERF_TALER_EXCHANGEDB_Cmd *cmd = &state->cmd[state->i]; + unsigned int index; + int save_index; + + save_index = cmd->details.load_random.index_save; + index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + state->cmd[save_index].details.save_array.nb_saved); + data_copy (&state->cmd[save_index].details.save_array.data_saved[index], + &cmd->exposed); +} + + +/** + * Iterate over the commands, acting accordingly at each step + * + * @param state the current state of the interpreter + */ +static int +interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) +{ + for (state->i=0; PERF_TALER_EXCHANGEDB_CMD_END != state->cmd[state->i].command; state->i++) + { + switch (state->cmd[state->i].command) + { + case PERF_TALER_EXCHANGEDB_CMD_END: + return GNUNET_YES; + + case PERF_TALER_EXCHANGEDB_CMD_DEBUG: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s\n", + state->cmd[state->i].label); + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOOP: + break; + + case PERF_TALER_EXCHANGEDB_CMD_END_LOOP: + interpret_end_loop (state); + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_TIME: + state->cmd[state->i].exposed.data.time = + GNUNET_new (struct GNUNET_TIME_Absolute); + *state->cmd[state->i].exposed.data.time = + GNUNET_TIME_absolute_get (); + break; + + case PERF_TALER_EXCHANGEDB_CMD_GAUGER: + { + unsigned int start_index; + unsigned int stop_index; + float ips; + struct GNUNET_TIME_Absolute start; + struct GNUNET_TIME_Absolute stop; + struct GNUNET_TIME_Relative elapsed; + + start_index = state->cmd[state->i].details.gauger.index_start; + stop_index = state->cmd[state->i].details.gauger.index_stop; + start = *state->cmd[start_index].exposed.data.time; + stop = *state->cmd[stop_index].exposed.data.time; + elapsed = GNUNET_TIME_absolute_get_difference (start, + stop); + ips = (1.0 * state->cmd[state->i].details.gauger.divide) / (elapsed.rel_value_us/1000000.0); + GAUGER (state->cmd[state->i].details.gauger.category, + state->cmd[state->i].details.gauger.description, + ips, + state->cmd[state->i].details.gauger.unit); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION: + state->session = state->plugin->get_session (state->plugin->cls, GNUNET_YES); + break; + + case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION: + state->plugin->start (state->plugin->cls, state->session); + break; + + case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION: + state->plugin->commit (state->plugin->cls, state->session); + break; + + case PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION: + state->plugin->rollback (state->plugin->cls, + state->session); + break; + + case PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY: + interpret_save_array (state); + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY: + interpret_load_array (state); + break; + + case PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM: + interprete_load_random (state); + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT: + { + int coin_index; + struct TALER_EXCHANGEDB_Deposit *deposit; + + coin_index = state->cmd[state->i].details.create_deposit.index_coin; + deposit = PERF_TALER_EXCHANGEDB_deposit_init (state->cmd[coin_index].exposed.data.coin); + GNUNET_assert (NULL != deposit); + state->cmd[state->i].exposed.data.deposit = deposit; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT: + { + int deposit_index; + int ret; + struct TALER_EXCHANGEDB_Deposit *deposit; + + deposit_index = state->cmd[state->i].details.insert_deposit.index_deposit; + deposit = state->cmd[deposit_index].exposed.data.deposit; + ret = state->plugin->insert_deposit (state->plugin->cls, + state->session, + deposit); + GNUNET_assert (GNUNET_SYSERR != ret); + state->cmd[state->i].exposed.data.deposit = deposit; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT: + { + unsigned int source_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Data *data; + + source_index = state->cmd[state->i].details.get_deposit.index_deposit; + data = &state->cmd[source_index].exposed; + ret = state->plugin->have_deposit (state->plugin->cls, + state->session, + data->data.deposit); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE: + { + struct PERF_TALER_EXCHANGEDB_Reserve *reserve; + + reserve = PERF_TALER_EXCHANGEDB_reserve_init (); + state->cmd[state->i].exposed.data.reserve = reserve; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE: + { + unsigned int reserve_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Reserve *reserve; + json_t *details = NULL; + + reserve_index = state->cmd[state->i].details.insert_reserve.index_reserve; + reserve = state->cmd[reserve_index].exposed.data.reserve; + details = json_pack ("{s:i}","justification", + GNUNET_CRYPTO_random_u32 ( + GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX)); + GNUNET_assert (NULL != details); + ret = state->plugin->reserves_in_insert (state->plugin->cls, + state->session, + &reserve->reserve.pub, + &reserve->reserve.balance, + GNUNET_TIME_absolute_get (), + details); + GNUNET_assert (GNUNET_SYSERR != ret); + json_decref (details); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE: + { + unsigned int reserve_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Data *data; + + + reserve_index = state->cmd[state->i].details.get_reserve.index_reserve; + data = &state->cmd[reserve_index].exposed; + ret = state->plugin->reserve_get (state->plugin->cls, + state->session, + &data->data.reserve->reserve); + GNUNET_assert (GNUNET_OK == ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY: + { + unsigned int reserve_index; + struct TALER_EXCHANGEDB_ReserveHistory *history; + struct PERF_TALER_EXCHANGEDB_Data *data; + + reserve_index = state->cmd[state->i].details.get_reserve_history.index_reserve; + data = &state->cmd[reserve_index].exposed; + history = state->plugin->get_reserve_history (state->plugin->cls, + state->session, + &data->data.reserve->reserve.pub); + GNUNET_assert (NULL != history); + state->plugin->free_reserve_history (state->plugin->cls, + history); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION: + { + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = + PERF_TALER_EXCHANGEDB_denomination_init (); + GNUNET_assert (NULL != dki); + state->cmd[state->i].exposed.data.dki = dki; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION: + { + unsigned int denom_index; + int ret; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki ; + + denom_index = state->cmd[state->i].details.insert_denomination.index_denom; + dki = state->cmd[denom_index].exposed.data.dki; + ret = state->plugin->insert_denomination_info (state->plugin->cls, + state->session, + &dki->denom_pub, + &dki->issue); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION: + { + unsigned int denom_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Data *data; + + denom_index = state->cmd[state->i].details.get_denomination.index_denom; + data = &state->cmd[denom_index].exposed; + ret = state->plugin->get_denomination_info (state->plugin->cls, + state->session, + &data->data.dki->denom_pub, + &data->data.dki->issue); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW: + { + unsigned int dki_index; + unsigned int reserve_index; + struct PERF_TALER_EXCHANGEDB_Coin *coin ; + + dki_index = state->cmd[state->i].details.create_withdraw.index_dki; + reserve_index = state->cmd[state->i].details.create_withdraw.index_reserve; + coin = PERF_TALER_EXCHANGEDB_coin_init (state->cmd[dki_index].exposed.data.dki, + state->cmd[reserve_index].exposed.data.reserve); + GNUNET_assert (NULL != coin); + state->cmd[state->i].exposed.data.coin = coin; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW: + { + unsigned int coin_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Coin *coin ; + + coin_index = state->cmd[state->i].details.insert_withdraw.index_coin; + coin = state->cmd[coin_index].exposed.data.coin; + ret = state->plugin->insert_withdraw_info (state->plugin->cls, + state->session, + &coin->blind); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW: + { + unsigned int source_index; + int ret; + struct PERF_TALER_EXCHANGEDB_Data *data; + + source_index = state->cmd[state->i].details.get_denomination.index_denom; + data = &state->cmd[source_index].exposed; + ret = state->plugin->get_withdraw_info (state->plugin->cls, + state->session, + &data->data.coin->blind.h_coin_envelope, + &data->data.coin->blind); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION: + { + unsigned int coin_index; + struct PERF_TALER_EXCHANGEDB_Coin *coin; + struct TALER_EXCHANGEDB_TransactionList *transactions; + + coin_index = state->cmd[state->i].details.get_coin_transaction.index_coin; + coin = state->cmd[coin_index].exposed.data.coin; + transactions = state->plugin->get_coin_transactions (state->plugin->cls, + state->session, + &coin->public_info.coin_pub); + GNUNET_assert (transactions != NULL); + state->plugin->free_coin_transaction_list (state->plugin->cls, + transactions); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION: + { + struct GNUNET_HashCode *hash; + struct TALER_EXCHANGEDB_RefreshSession *refresh_session; + + hash = GNUNET_new (struct GNUNET_HashCode); + refresh_session = PERF_TALER_EXCHANGEDB_refresh_session_init (); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + hash); + state->plugin->create_refresh_session (state->session, + state->session, + hash, + refresh_session); + state->cmd[state->i].exposed.data.session_hash = hash; + PERF_TALER_EXCHANGEDB_refresh_session_free (refresh_session); + GNUNET_free (refresh_session); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION: + { + unsigned int hash_index; + struct GNUNET_HashCode *hash; + struct TALER_EXCHANGEDB_RefreshSession refresh; + + hash_index = state->cmd[state->i].details.get_refresh_session.index_hash; + hash = state->cmd[hash_index].exposed.data.session_hash; + state->plugin->get_refresh_session (state->session, + state->session, + hash, + &refresh); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT: + { + unsigned int hash_index; + unsigned int coin_index; + struct GNUNET_HashCode *hash; + struct TALER_EXCHANGEDB_RefreshMelt *melt; + struct PERF_TALER_EXCHANGEDB_Coin *coin; + + hash_index = state->cmd[state->i].details.insert_refresh_melt.index_hash; + coin_index = state->cmd[state->i].details.insert_refresh_melt.index_coin; + hash = state->cmd[hash_index].exposed.data.session_hash; + coin = state->cmd[coin_index].exposed.data.coin; + melt = PERF_TALER_EXCHANGEDB_refresh_melt_init (hash, + coin); + state->plugin->insert_refresh_melt (state->plugin->cls, + state->session, + 1, + melt); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT: + { + int ret; + unsigned int hash_index; + struct GNUNET_HashCode *hash; + struct TALER_EXCHANGEDB_RefreshMelt melt; + + hash_index = cmd_find (state->cmd, + state->cmd[state->i].details.get_refresh_melt.label_hash); + hash = state->cmd[hash_index].exposed.data.session_hash; + ret = state->plugin->get_refresh_melt (state->plugin->cls, + state->session, + hash, + 1, + &melt); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER: + { + unsigned int hash_index; + unsigned int denom_index; + struct GNUNET_HashCode *session_hash; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *denom; + + hash_index = state->cmd[state->i].details.insert_refresh_order.index_hash; + denom_index = state->cmd[state->i].details.insert_refresh_order.index_denom; + session_hash = state->cmd[hash_index].exposed.data.session_hash; + denom = state->cmd[denom_index].exposed.data.dki; + state->plugin->insert_refresh_order (state->plugin->cls, + state->session, + session_hash, + 1, + &denom->denom_pub); + + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER: + { + int hash_index; + struct GNUNET_HashCode *hash; + struct TALER_DenominationPublicKey denom_pub; + + hash_index = state->cmd[state->i].details.get_refresh_order.index_hash; + hash = state->cmd[hash_index].exposed.data.session_hash; + state->plugin->get_refresh_order (state->plugin->cls, + state->session, + hash, + 1, + &denom_pub); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN: + { + int ret; + unsigned int hash_index; + struct TALER_EXCHANGEDB_RefreshCommitCoin *refresh_commit; + + hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash; + refresh_commit = PERF_TALER_EXCHANGEDB_refresh_commit_coin_init (); + ret = state->plugin->insert_refresh_commit_coins (state->plugin->cls, + state->session, + state->cmd[hash_index].exposed.data.session_hash, + 1, + 1, + refresh_commit); + GNUNET_assert (GNUNET_OK == ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN: + { + unsigned int hash_index; + struct TALER_EXCHANGEDB_RefreshCommitCoin refresh_commit; + + hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash; + state->plugin->get_refresh_commit_coins (state->plugin->cls, + state->session, + state->cmd[hash_index].exposed.data.session_hash, + 1, + 1, + &refresh_commit); + + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK: + { +// unsigned int hash_index; +// +// hash_index = state->cmd[state->i].details.insert_refresh_commit_link.index_hash; + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK: + { + int ret; + unsigned int hash_index; + struct TALER_EXCHANGEDB_RefreshCommitCoin commit_coin; + + hash_index = state->cmd[state->i].details.get_refresh_commit_link.index_hash; + ret = state->plugin->get_refresh_commit_coins(state->plugin->cls, + state->session, + state->cmd[hash_index].exposed.data.session_hash, + 1, + 1, + &commit_coin); + GNUNET_assert (GNUNET_SYSERR != ret); + } + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT: + break; + + case PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT: + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST: + break; + + case PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER: + break; + + } + } + return GNUNET_OK; +} + + +/** + * Runs the commands given in @a cmd, working with + * the database referenced by @a db_plugin + * + * @param db_plugin the connection to the database + * @param cmd the commands to run + */ +int +PERF_TALER_EXCHANGEDB_interpret (struct TALER_EXCHANGEDB_Plugin *db_plugin, + struct PERF_TALER_EXCHANGEDB_Cmd cmd[]) +{ + int ret; + struct PERF_TALER_EXCHANGEDB_interpreter_state state = + {.i = 0, .cmd = cmd, .plugin = db_plugin}; + + ret = cmd_init (cmd); + if (GNUNET_SYSERR == ret) + return ret; + state.session = db_plugin->get_session (db_plugin->cls, + GNUNET_YES); + GNUNET_assert (NULL != state.session); + ret = interpret (&state); + cmd_clean (cmd); + return ret; +} + + +/** + * Initialize the database and run the benchmark + * + * @param benchmark_name the name of the benchmark, displayed in the logs + * @param configuration_file path to the taler configuration file to use + * @param init the commands to use for the database initialisation, + * if #NULL the standard initialization is used + * @param benchmark the commands for the benchmark + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +PERF_TALER_EXCHANGEDB_run_benchmark (const char *benchmark_name, + const char *configuration_file, + struct PERF_TALER_EXCHANGEDB_Cmd *init, + struct PERF_TALER_EXCHANGEDB_Cmd *benchmark) +{ + struct TALER_EXCHANGEDB_Plugin *plugin; + struct GNUNET_CONFIGURATION_Handle *config; + int ret = 0; + struct PERF_TALER_EXCHANGEDB_Cmd init_def[] = + { + // Denomination used to create coins + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("00 - Start of interpreter"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop", + PERF_TALER_EXCHANGEDB_NB_DENOMINATION_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", + "01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", + "01 - denomination loop", + "01 - denomination", + PERF_TALER_EXCHANGEDB_NB_DENOMINATION_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "01 - denomination loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("01 - init denomination complete"), + // End of initialization + // Reserve initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop", + PERF_TALER_EXCHANGEDB_NB_RESERVE_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert", + "02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", + "02 - init reserve loop", + "02 - reserve", + PERF_TALER_EXCHANGEDB_NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "02 - init reserve loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("02 - reserve init complete"), + // End reserve init + // Withdrawal initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop", + PERF_TALER_EXCHANGEDB_NB_WITHDRAW_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", + "03 - init withdraw loop", + "01 - save denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", + "03 - init withdraw loop", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", + "03 - denomination load", + "03 - reserve load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert", + "03 - withdraw"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION (""), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - save coin", + "03 - init withdraw loop", + "03 - withdraw", + PERF_TALER_EXCHANGEDB_NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("", + "03 - init withdraw loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("03 - withdraw init complete"), + //End of withdrawal initialization + //Deposit initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop", + PERF_TALER_EXCHANGEDB_NB_DEPOSIT_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - denomination load", + "04 - deposit init loop", + "03 - save coin"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - deposit", + "04 - denomination load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", + "04 - deposit init loop", + "04 - deposit", + PERF_TALER_EXCHANGEDB_NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("04 - deposit init loop end", + "04 - deposit init loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("04 - deposit init complete"), + // End of deposit initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_END ("end") + }; + + GNUNET_log_setup (benchmark_name, + "INFO", + NULL); + config = GNUNET_CONFIGURATION_create (); + + ret = GNUNET_CONFIGURATION_load (config, + configuration_file); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error parsing configuration file\n"); + return GNUNET_SYSERR; + } + plugin = TALER_EXCHANGEDB_plugin_load (config); + if (NULL == plugin) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error connectiong to the database\n"); + return ret; + } + ret = plugin->create_tables (plugin->cls, + GNUNET_YES); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error while creating the database architecture\n"); + return ret; + } + /* + * Running the initialization + */ + if (NULL == init) + { + init = init_def; + } + ret = PERF_TALER_EXCHANGEDB_interpret (plugin, + init); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error during database initialization\n"); + return ret; + } + /* + * Running the benchmark + */ + ret = PERF_TALER_EXCHANGEDB_interpret (plugin, + benchmark); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error while runing the benchmark\n"); + return ret; + } + /* Drop tables */ + { + struct TALER_EXCHANGEDB_Session *session; + + session = plugin->get_session (plugin->cls, + GNUNET_YES); + ret = plugin->drop_temporary (plugin->cls, + session); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error cleaning the database\n"); + return ret; + } + } + TALER_EXCHANGEDB_plugin_unload (plugin); + GNUNET_CONFIGURATION_destroy (config); + return ret; +} diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.h b/src/exchangedb/perf_taler_exchangedb_interpreter.h new file mode 100644 index 000000000..a83251c60 --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb_interpreter.h @@ -0,0 +1,1319 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchangedb/perf_taler_exchangedb_interpreter.h + * @brief Library for performance analysis of the Taler database + * @author Nicolas Fournier + * + * This library contains functions and macro alowing Taler performance analysis + * to be written with ease. + * To do so, create a #PERF_TALER_EXCHANGEDB_Cmd array and fill it with the commands + * to execute in chronological order. Some command have an exposed variable wich + * can be reused in other commands. + * Macros are available to make the use much easier so feel free to use them + * to initialize your own command array. + */ + +#ifndef __PERF_TALER_EXCHANGEDB_INTERPRETER_H__ +#define __PERF_TALER_EXCHANGEDB_INTERPRETER_H__ + +#include <sys/time.h> +#include "taler_exchangedb_plugin.h" + + +#define PERF_TALER_EXCHANGEDB_NB_DENOMINATION_INIT 10 +#define PERF_TALER_EXCHANGEDB_NB_DENOMINATION_SAVE 10 + +#define PERF_TALER_EXCHANGEDB_NB_RESERVE_INIT 100 +#define PERF_TALER_EXCHANGEDB_NB_RESERVE_SAVE 10 + +#define PERF_TALER_EXCHANGEDB_NB_DEPOSIT_INIT 100 +#define PERF_TALER_EXCHANGEDB_NB_DEPOSIT_SAVE 10 + +#define PERF_TALER_EXCHANGEDB_NB_WITHDRAW_INIT 100 +#define PERF_TALER_EXCHANGEDB_NB_WITHDRAW_SAVE 10 + + +/** + * Marks the end of the command chain + * + * @param _label The label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_END(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_END, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE \ +} + + +/** + * Prints @ _label to stdout + * + * @param _label The label of the command, + * will be logged each time the command runs + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_DEBUG, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE \ +} + +/** + * The begining of a loop + * + * @param _label the label of the loop + * @param _iter the number of iterations of the loop + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP(_label, _iter) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_LOOP , \ + .label = _label , \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE , \ + .details.loop = { \ + .max_iterations = _iter , \ + .curr_iteration = 0 } \ +} + +/** + * Marks the end of the loop @_label_loop + * + * @param _label the label of the command + * @param _label_loop the label of the loop closed by this command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP(_label, _label_loop) \ +{\ + .command = PERF_TALER_EXCHANGEDB_CMD_END_LOOP , \ + .label = _label , \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE , \ + .details.end_loop.label_loop = _label_loop \ +} + +/** + * Saves the time of execution to use for logging with Gauger + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_TIME, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_TIME \ +} + +/** + * Commits the duration between @a _label_start and @a _label_stop + * to Gauger with @a _description explaining what was measured. + * + * @param _label the label of this command + * @param _label_start label of the start of the measurment + * @param _label_stop label of the end of the measurment + * @param _description description of the measure displayed in Gauger + * @param _unit the unit of the data measured, typicly something/sec + * @param _divide number of measurments in the interval + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER(_label, _label_start, _label_stop, _category, _description, _unit, _divide) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GAUGER, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.gauger = { \ + .label_start = _label_start, \ + .label_stop = _label_stop, \ + .category = _category, \ + .description = _description, \ + .unit = _unit, \ + .divide = _divide, \ + } \ +} + +/** + * Initiate a database transaction + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ +} + +/** + * Commits a database transaction + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ +} + +/** + * Abort the current transaction + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_ABORT_TRANSACTION(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION, \ + .label = _label, + +/** + * Saves randomly selected items from @a _label_save + * Saved items can latter be access using #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY + * + * @param _label the label of the command, used by other commands to reference it + * @param _label_loop the label of the loop the array iterates over + * @param _label_save the label of the command which outout is saved by this command + * @param _nb_saved the total number of items to be saved + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY(_label, _label_loop, _label_save, _nb_saved) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.save_array = { \ + .label_loop = _label_loop, \ + .label_save = _label_save, \ + .nb_saved = _nb_saved, \ + } \ +} + +/** + * Loads data from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY to allow other + * commands to access it + * + * @param _label the label of this command, referenced by commands to access it's outpout + * @param _label_loop the label of the loop to iterate over + * @param _label_save the label of the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY providing data + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY(_label, _label_loop, _label_save) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.load_array = { \ + .label_loop = _label_loop, \ + .label_save = _label_save \ + } \ +} + +/** + * Create a denomination key to use + * Exposes a #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO to be used by other commands + * @exposed #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO + * + * @param _label the label of this command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_DENOMINATION_INFO, \ +} + +/** + * Inserts informations about a denomination key in the database + * + * @param _label the label of this command + * @param _label_denom the label of the denomination to insert + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION(_label, _label_denom) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.insert_denomination.label_denom = _label_denom, \ +} + +/** + * Polls the database about informations regarding a specific denomination key + * + * @param _label the label of this command + * @param _label_denom the label of the command providing information about the denomination key + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DENOMINATION(_label, _label_denom) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_denomination.label_denom = _label_denom \ +} + +/** + * Create a reserve to be used later + * Exposes a #PERF_TALER_EXCHANGEDB_RESERVE + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_RESERVE \ +} + +/** + * Insert a new reserve in the database containing 1000 Euros + * + * @param _label the name of this command + * @param _label_reserve the label of the reserve to insert + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE(_label, _label_reserve) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.insert_reserve.label_reserve = _label_reserve \ +} + +/** + * Polls the database for a secific reserve's details + * + * @param _label the label of this command + * @param _label_reserve the reserve to poll + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE(_label, _label_reserve) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_reserve.label_reserve = _label_reserve \ +} + +/** + * Polls the database for the history of a reserve + * + * @param _label the label of the command + * @param _label_reserve the reserve to examine + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY(_label, _label_reserve) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_reserve_history.label_reserve = _label_reserve \ +} + +/** + * Creates a coin to be used later + * + * @param _label the label of this command + * @param _label_dki denomination key used to sign the coin + * @param _label_reserve reserve used to emmit the coin + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW(_label, _label_dki, _label_reserve) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_COIN, \ + .details.create_withdraw = {\ + .label_dki = _label_dki, \ + .label_reserve = _label_reserve, \ + } \ +} + +/** + * Inserts informations about a withdrawal in the database + * + * @exposes #PERF_TALER_EXCHANGEDB_COIN + * + * @param _label the label of this command + * @param _label_coin the coin to insert + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW(_label, _label_coin) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.insert_withdraw.label_coin = _label_coin\ +} + + +/** + * Polls the database about informations regarding a specific withdrawal + * + * @param _label the label of this command + * @param _label_coin the coin to check + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_WITHDRAW(_label, _label_coin) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_withdraw.label_coin = _label_coin, \ +} + + +/** + * The /reserve/withdraw api call + * + * Exposes #PERF_TALER_EXCHANGEDB_COIN + * + * @param _label the label of this command + * @param _label_dki the denomination of the created coin + * @param _label_reserve the reserve used to provide currency + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_WITHDRAW_SIGN(_label, _label_dki, _label_reserve) \ + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW (_label "withdraw", \ + _label_dki, \ + _label_reserve), \ + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DENOMINATION(_label "withdraw info", \ + _label_dki), \ + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_RESERVE_HISTORY(_label "reserve_history", \ + _label_reserve), \ + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW(_label "insert withdraw", \ + _label "withdraw") + +/** + * Create a deposit for use later + * @exposes #PERF_TALER_EXCHANGEDB_DEPOSIT + * + * @param _label the label of this command + * @param _label_coin the coin used to pay + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT(_label, _label_coin) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_DEPOSIT, \ + .details.create_deposit.label_coin = _label_coin, \ +} + +/** + * Insert a deposit into the database + * + * @param _label the label of this command + * @param _label_deposit the deposit inseerted + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT(_label, _label_deposit) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT,\ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.insert_deposit.label_deposit = _label_deposit, \ +} + +/** + * Check if a deposit is in the database + * + * @param _label the label of this command + * @param _label_deposit the deposit to use + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_DEPOSIT(_label, _label_deposit) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_deposit.label_deposit = _label_deposit \ +} + +/** + * Access the transaction history of a coin + * + * @param _label the label of the command + * @param _label_coin the coin which history is checked + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION(_label, _label_coin) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE, \ + .details.get_coin_transaction.label_coin = _label_coin \ +} + +/** + * The /deposit api call + * + * @param _label the label of the command + * @param _label_coin the coin used for the deposit + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_DEPOSIT(_label, _label_coin) \ + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_COIN_TRANSACTION (_label "coin history", \ + _label_coin), \ + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT (_label "deposit", \ + _label_coin), \ + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT (_label "insert", \ + _label "deposit") +/** + * Insert informations about a refresh session + * melts one coin into another + * + * @param _label the label of the command + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_REFRESH_SESSION(_label) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_REFRESH_HASH \ +} + +/** + * Get informations about a refresh session + * + * @param _label the label of the command + * @param _label_hash the label of the hash to search + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_REFRESH_SESSION(_label, \ + _label_hash) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION, \ + .label = _label, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE \ +} + +/** + * Insert a melt operation in the database + * + * @param _label the label of the command + * @param _label_hash the label of the hash of the session + * @param _label_coin the label of the coin to melt + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_REFRESH_MELT(_label, \ + _label_hash, \ + _label_coin) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT, \ + .label = _label, \ + .details.insert_refresh_melt.label_hash = _label_hash, \ + .details.insert_refresh_melt.label_coin = _label_coin, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE \ +} + +/** + * Get informations about a melt operation + * + * @param _label the label of the command + * @param _label_hash the label of the hash of the refresh session + */ +#define PERF_TALER_EXCHANGEDB_INIT_CMD_GET_REFRESH_MELT(_label, \ + _label_hash) \ +{ \ + .command = PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT, \ + .label = _label, \ + .detail.get_refresh_melt.label_hash = _label_hash, \ + .exposed.type = PERF_TALER_EXCHANGEDB_NONE \ +} + +/** + * The type of data stored in #PERF_TALER_EXCHANGEDB_Memory + */ +enum PERF_TALER_EXCHANGEDB_Type +{ + PERF_TALER_EXCHANGEDB_NONE, + PERF_TALER_EXCHANGEDB_TIME, + PERF_TALER_EXCHANGEDB_DENOMINATION_INFO, + PERF_TALER_EXCHANGEDB_RESERVE, + PERF_TALER_EXCHANGEDB_COIN, + PERF_TALER_EXCHANGEDB_DEPOSIT, + PERF_TALER_EXCHANGEDB_REFRESH_HASH, + PERF_TALER_EXCHANGEDB_REFRESH_MELT +}; + + +/** + * Structure used to handle several data type + */ +struct PERF_TALER_EXCHANGEDB_Data +{ + enum PERF_TALER_EXCHANGEDB_Type type; + + /** + * Storage for a variety of data type + * The data saved should match #type + */ + union PERF_TALER_EXCHANGEDB_Memory + { + /** #PERF_TALER_EXCHANGEDB_TIME */ + struct GNUNET_TIME_Absolute *time; + /** #PERF_TALER_EXCHANGEDB_DEPOSIT */ + struct TALER_EXCHANGEDB_Deposit *deposit; + /** #PERF_TALER_EXCHANGEDB_COIN */ + struct PERF_TALER_EXCHANGEDB_Coin *coin; + /** #PERF_TALER_EXCHANGEDB_RESERVE */ + struct PERF_TALER_EXCHANGEDB_Reserve *reserve; + /** #PERF_TALER_EXCHANGEDB_DENOMINATION_INFO */ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; + /** #PERF_TALER_EXCHANGEDB_REFRESH_HASH */ + struct GNUNET_HashCode *session_hash; + /** #PERF_TALER_EXCHANGEDB_REFRESH_MELT */ + struct TALER_EXCHANGEDB_RefreshMelt *refresh_melt; + } data; +}; + + +/** + * Name of the command + */ +enum PERF_TALER_EXCHANGEDB_CMD_Name +{ + /** + * All comand chain must hace this as their last command + */ + PERF_TALER_EXCHANGEDB_CMD_END, + + /** + * Prints it's label + */ + PERF_TALER_EXCHANGEDB_CMD_DEBUG, + + /** + * Define the start of al command chain loop + */ + PERF_TALER_EXCHANGEDB_CMD_LOOP, + + /** + * Define the end of a command chain loop + */ + PERF_TALER_EXCHANGEDB_CMD_END_LOOP, + + /** + * Save the time at which the command was executed + */ + PERF_TALER_EXCHANGEDB_CMD_GET_TIME, + + /** + * Upload performance to Gauger + */ + PERF_TALER_EXCHANGEDB_CMD_GAUGER, + + /** + * Start a new session + */ + PERF_TALER_EXCHANGEDB_CMD_NEW_SESSION, + + /** + * Start a database transaction + */ + PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION, + + /** + * End a database transaction + */ + PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION, + + /** + * Abort a transaction started with #PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION + */ + PERF_TALER_EXCHANGEDB_CMD_ABORT_TRANSACTION, + + /** + * Saves random deposits from a loop + */ + PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY, + + /** + * Load items saved earlier in a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY + * The items are loaded in a random order, but all of them will be loaded + */ + PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY, + + /** + * Loads a random item from a #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY + * A random item is loaded each time the command is run + */ + PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM, + + /** + * Create a denomination to be used later + */ + PERF_TALER_EXCHANGEDB_CMD_CREATE_DENOMINATION, + + /** + * Insert informations about a denomination key in the database + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION, + + /** + * Polls the database for informations about a specific denomination key + */ + PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION, + + /** + * Create a reserve to be used later + */ + PERF_TALER_EXCHANGEDB_CMD_CREATE_RESERVE, + + /** + * Insert currency in a reserve / Create a reserve + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE, + + /** + * Get Informations about a reserve + */ + PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE, + + /** + * Get the history of a reserve + */ + PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY, + + /** + * Create a withdrawal to be used later + */ + PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW, + + /** + * Insert informations about a withdrawal in the database + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW, + + /** + * Pulls informations about a withdrawal from the database + */ + PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW, + + /** + * Get the list of all transactions the coin has been in + */ + PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION, + + /** + * Create a deposit to be used later + */ + PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT, + + /** + * Insert a deposit into the database + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT, + + /** + * Check if a deposit is in the database + */ + PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT, + + /** + * Create a refresh session + * The number of melted coins is 1, + * The number of exchangeed coins is 1 + */ + PERF_TALER_EXCHANGEDB_CMD_CREATE_REFRESH_SESSION, + + /** + * Get a refresh session informations + */ + PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION, + + /** + * Insert a refresh melt + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT, + + /** + * Get informations about a refresh melt operation + */ + PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT, + + /** + * Insert a melt refresh order + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER, + + /** + * Get informations about a refresh order + */ + PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER, + + /** + * Insert refresh commit coin + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN, + + /** + * Get refresh commit coin + */ + PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN, + + /** + * Insert refresh commit link + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK, + + /** + * Get refresh commit link + */ + PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK, + + /** + * Get information avout the melt commit + */ + PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT, + + /** + * Insert a new coin into the database after a melt operation + */ + PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT, + + /** + * Get the link data list of a coin + */ + PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST, + + /** + * Get the shared secret and the transfere public key + */ + PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER + +}; + + +/** + * Contains extra data required for any command + */ +union PERF_TALER_EXCHANGEDB_CMD_Details +{ + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_LOOP command + */ + struct PERF_TALER_EXCHANGEDB_CMD_loopDetails + { + /** + * Maximum number of iteration in the loop + */ + const unsigned int max_iterations; + + /** + * The current iteration of the loop + */ + unsigned int curr_iteration; + } loop; + + /** + * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_END_LOOP command + */ + struct PERF_TALER_EXCHANGEDB_CMD_endLoopDetails + { + /** + * Label of the loop closed by the command + */ + const char *label_loop; + unsigned int index_loop; + } end_loop; + + /** + * Details about the #PERF_TALER_EXCHANGEDB_CMD_GAUGER command + */ + struct PERF_TALER_EXCHANGEDB_CMD_gaugerDetails + { + /** + * Label of the starting timestamp + */ + const char *label_start; + unsigned int index_start; + + /** + * Label of the ending timestamp + */ + const char *label_stop; + unsigned int index_stop; + + /** + * The category of the measurment + */ + const char *category; + + /** + * Description of the metric, used in Gauger + */ + const char *description; + + /** + * The name of the metric beeing used + */ + const char *unit; + + /** + * Constant the result needs to be divided by + * to get the result per unit + */ + float divide; + } gauger; + + /** + * Contains extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY command + */ + struct PERF_TALER_EXCHANGEDB_CMD_saveArrayDetails + { + /** + * Number of items to save + */ + unsigned int nb_saved; + + /** + * Number of items already saved + */ + unsigned int index; + + /** + * Label of the loop it is attached to + */ + const char *label_loop; + unsigned int index_loop; + + /** + * Label of the command exposing the item + */ + const char *label_save; + unsigned int index_save; + + /** + * Array of data saved + */ + struct PERF_TALER_EXCHANGEDB_Data *data_saved; + + /** + * Type of the data that will be stored in @a data_saved, for + * 'static' type checking. + */ + enum PERF_TALER_EXCHANGEDB_Type type_saved; + + } save_array; + + /** + * Extra data required for the #PERF_TALER_EXCHANGEDB_CMD_LOAD_ARRAY command + */ + struct PERF_TALER_EXCHANGEDB_CMD_loadArrayDetails + { + /** + * The loop in which the command is located + */ + const char *label_loop; + unsigned int index_loop; + + /** + * Label of the command where the items were saved + */ + const char *label_save; + unsigned int index_save; + + /** + * A permutation array used to randomize the order the items are loaded in + */ + unsigned int *permutation; + } load_array; + + /** + * Contains data for the #PERF_TALER_EXCHANGEDB_CMD_LOAD_RANDOM command + */ + struct PERF_TALER_EXCHANGEDB_CMD_loadRandomDetails + { + /** + * The label of the #PERF_TALER_EXCHANGEDB_CMD_SAVE_ARRAY the items will be extracted from + */ + const char *label_save; + unsigned int index_save; + } load_random; + + /** + * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_INSERT_DENOMINATION command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertDenominationDetails + { + /** + * The label of the source of the denomination to insert + */ + const char *label_denom; + unsigned int index_denom; + } insert_denomination; + + /** + * Extra data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_DENOMINATION command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getDenominationDetails + { + /** + * The label of the source of the denomination to check + */ + const char *label_denom; + unsigned int index_denom; + } get_denomination; + + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_RESERVE command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertReserveDetails + { + /** + * The label of the source of the reserve to insert + */ + const char *label_reserve; + unsigned int index_reserve; + } insert_reserve; + + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getReserveDetails + { + /** + * The label of the source of the reserve to check + */ + const char *label_reserve; + unsigned int index_reserve; + } get_reserve; + + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_RESERVE_HISTORY command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getReserveHistoryDetails + { + /** + * The label of the source of the reserve to check + */ + const char *label_reserve; + unsigned int index_reserve; + } get_reserve_history; + + /** + * Extra data related to the #PERF_TALER_EXCHANGEDB_CMD_CREATE_WITHDRAW command + */ + struct PERF_TALER_EXCHANGEDB_CMD_createWithdrawDetails + { + /** + * label of the denomination key used to sign the coin + */ + const char *label_dki; + unsigned int index_dki; + + /** + * label of the reserve the money to exchange the coin comes from + */ + const char *label_reserve; + unsigned int index_reserve; + } create_withdraw; + + /** + * data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_WITHDRAW + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertWithdrawDetails + { + /** + * label of the source for the coin information + */ + const char *label_coin; + unsigned int index_coin; + } insert_withdraw; + + /** + * data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_WITHDRAW + */ + struct PERF_TALER_EXCHANGEDB_CMD_getWithdraw + { + /** + * label of the source for the coin information + */ + const char *label_coin; + unsigned int index_coin; + } get_withdraw; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_COIN_TRANSACTION command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getCoinTransactionDetails + { + /** + * The coin which history is checked + */ + const char *label_coin; + unsigned int index_coin; + } get_coin_transaction; + + /** + * Data used by the #PERF_TALER_EXCHANGEDB_CMD_CREATE_DEPOSIT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_createDepositDetails + { + /** + * Label of the source where the reserve used to create the coin is + */ + const char *label_coin; + unsigned int index_coin; + } create_deposit; + + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_DEPOSIT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertDepositDetails + { + /** + * The label of the source of the deposit to check + */ + const char *label_deposit; + unsigned int index_deposit; + } insert_deposit; + + /** + * Extra data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getDepositDetails + { + /** + * The label of the source of the deposit to check + */ + const char *label_deposit; + unsigned int index_deposit; + } get_deposit; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_SESSION command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getRefreshSessionDetails + { + /** + * label of the source of the hash of the session + */ + const char *label_hash; + unsigned int index_hash; + } get_refresh_session; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_MELT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshMeltDetails + { + /** + * The label of the hash of the refresh session + */ + const char *label_hash; + unsigned int index_hash; + + /** + * The label of the coin to melt + */ + const char *label_coin; + unsigned int index_coin; + } insert_refresh_melt; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_MELT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getRefreshMeltDetails + { + /** + * The label of the hash of the session + */ + const char *label_hash; + unsigned int index_hash; + } get_refresh_melt; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_ORDER command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOrderDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + + /** + * The new coin denomination + */ + const char *label_denom; + unsigned int index_denom; + } insert_refresh_order; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_ORDER command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getRefreshOrderDetails + { + /** + * The session hash + */ + const char *label_hash; + unsigned int index_hash; + + } get_refresh_order; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_COIN command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitCoinDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + + } insert_refresh_commit_coin; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_COIN command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitCoinDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + + } get_refresh_commit_coin; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_COMMIT_LINK command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshCommitLinkDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + + } insert_refresh_commit_link; + + /** + * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_REFRESH_COMMIT_LINK command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getRefreshCommitLinkDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + } get_refresh_commit_link; + + /** + * Data requiered for the #PERF_TALER_EXCHANGEDB_CMD_GET_MELT_COMMITMENT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getMeltCommitmentDaetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + } get_melt_commitment; + + /** + * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_INSERT_REFRESH_OUT command + */ + struct PERF_TALER_EXCHANGEDB_CMD_insertRefreshOutDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + } insert_refresh_out; + + /** + * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_LINK_DATA_LIST command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getLinkDataListDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + } get_link_data_list; + + /** + * Data requiered by the #PERF_TALER_EXCHANGEDB_CMD_GET_TRANSFER command + */ + struct PERF_TALER_EXCHANGEDB_CMD_getTransferDetails + { + /** + * The refresh session hash + */ + const char *label_hash; + unsigned int index_hash; + } get_transfer; + +}; + + +/** + * Command to be interpreted. + */ +struct PERF_TALER_EXCHANGEDB_Cmd +{ + /** + * Type of the command + */ + enum PERF_TALER_EXCHANGEDB_CMD_Name command; + + /** + * Label to refer to the command + */ + const char *label; + + /** + * Command specific data + */ + union PERF_TALER_EXCHANGEDB_CMD_Details details; + + /** + * Data easily accessible + */ + struct PERF_TALER_EXCHANGEDB_Data exposed; +}; + + +/** + * Run a benchmark + * + * @param benchmark_name the name of the benchmark, displayed in the logs + * @param configuration_file path to the taler configuration file to use + * @param init the commands to use for the database initialisation, + * if #NULL the standard initialization is used + * @param benchmark the commands for the benchmark + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +PERF_TALER_EXCHANGEDB_run_benchmark (const char *benchmark_name, + const char *configuration_file, + struct PERF_TALER_EXCHANGEDB_Cmd *init, + struct PERF_TALER_EXCHANGEDB_Cmd *benchmark); + + +/** + * Runs the command array @a cmd + * using @a db_plugin to connect to the database + * + * @param db_plugin the connection to the database + * @param cmd the commands to run + */ +int +PERF_TALER_EXCHANGEDB_interpret( + struct TALER_EXCHANGEDB_Plugin *db_plugin, + struct PERF_TALER_EXCHANGEDB_Cmd cmd[]); + + +/** + * Check if the given command array is syntaxicly correct + * This will check if the label are corrects but will not check if + * they are pointing to an apropriate command. + * + * @param cmd the command array to check + * @return #GNUNET_OK is @a cmd is correct; #GNUNET_SYSERR if it is'nt + */ +int +PERF_TALER_EXCHANGEDB_check (const struct PERF_TALER_EXCHANGEDB_Cmd *cmd); + +#endif diff --git a/src/exchangedb/perf_taler_exchangedb_values.h b/src/exchangedb/perf_taler_exchangedb_values.h new file mode 100644 index 000000000..c3b50fea2 --- /dev/null +++ b/src/exchangedb/perf_taler_exchangedb_values.h @@ -0,0 +1,25 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/perf_taler_exchangedb_values.h + * @brief Values for tweaking the performance analysis + * @author Nicolas Fournier + */ +#ifndef __PERF_TALER_EXCHANGEDB__VALUES_H__ +#define __PERF_TALER_EXCHANGEDB__VALUES_H__ + + +#endif diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c new file mode 100644 index 000000000..c8e689cfd --- /dev/null +++ b/src/exchangedb/plugin_exchangedb_common.c @@ -0,0 +1,162 @@ +/* + This file is part of TALER + Copyright (C) 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchangedb/plugin_exchangedb_common.c + * @brief Functions shared across plugins, this file is meant to be + * included in each plugin. + * @author Christian Grothoff + */ + +/** + * Free memory associated with the given reserve history. + * + * @param cls the @e cls of this struct with the plugin-specific state (unused) + * @param rh history to free. + */ +static void +common_free_reserve_history (void *cls, + struct TALER_EXCHANGEDB_ReserveHistory *rh) +{ + struct TALER_EXCHANGEDB_BankTransfer *bt; + struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc; + struct TALER_EXCHANGEDB_ReserveHistory *backref; + + while (NULL != rh) + { + switch(rh->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + bt = rh->details.bank; + if (NULL != bt->wire) + json_decref (bt->wire); + GNUNET_free (bt); + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + cbc = rh->details.withdraw; + GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key); + GNUNET_free (cbc); + break; + } + backref = rh; + rh = rh->next; + GNUNET_free (backref); + } +} + + +/** + * Free memory of the link data list. + * + * @param cls the @e cls of this struct with the plugin-specific state (unused) + * @param ldl link data list to release + */ +static void +common_free_link_data_list (void *cls, + struct TALER_EXCHANGEDB_LinkDataList *ldl) +{ + struct TALER_EXCHANGEDB_LinkDataList *next; + + while (NULL != ldl) + { + next = ldl->next; + GNUNET_free (ldl->link_data_enc); + GNUNET_free (ldl); + ldl = next; + } +} + + +/** + * Free linked list of transactions. + * + * @param cls the @e cls of this struct with the plugin-specific state (unused) + * @param list list to free + */ +static void +common_free_coin_transaction_list (void *cls, + struct TALER_EXCHANGEDB_TransactionList *list) +{ + struct TALER_EXCHANGEDB_TransactionList *next; + + while (NULL != list) + { + next = list->next; + + switch (list->type) + { + case TALER_EXCHANGEDB_TT_DEPOSIT: + json_decref (list->details.deposit->wire); + GNUNET_CRYPTO_rsa_public_key_free (list->details.deposit->coin.denom_pub.rsa_public_key); + GNUNET_CRYPTO_rsa_signature_free (list->details.deposit->coin.denom_sig.rsa_signature); + GNUNET_free (list->details.deposit); + break; + case TALER_EXCHANGEDB_TT_REFRESH_MELT: + GNUNET_free (list->details.melt); + break; + } + GNUNET_free (list); + list = next; + } +} + + +/** + * Free melt commitment data. + * + * @param cls the @e cls of this struct with the plugin-specific state (unused) + * @param mc data structure to free + */ +static void +common_free_melt_commitment (void *cls, + struct TALER_EXCHANGEDB_MeltCommitment *mc) +{ + unsigned int i; + unsigned int k; + + if (NULL != mc->melts) + { + for (i=0;i<mc->num_oldcoins;i++) + { + GNUNET_CRYPTO_rsa_signature_free (mc->melts[i].coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (mc->melts[i].coin.denom_pub.rsa_public_key); + } + GNUNET_free (mc->melts); + } + if (NULL != mc->denom_pubs) + { + for (i=0;i<mc->num_newcoins;i++) + if (NULL != mc->denom_pubs[i].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (mc->denom_pubs[i].rsa_public_key); + GNUNET_free (mc->denom_pubs); + } + for (k=0;k<TALER_CNC_KAPPA;k++) + { + if (NULL != mc->commit_coins[k]) + { + for (i=0;i<mc->num_newcoins;i++) + { + GNUNET_free (mc->commit_coins[k][i].refresh_link); + GNUNET_free (mc->commit_coins[k][i].coin_ev); + } + GNUNET_free (mc->commit_coins[k]); + } + GNUNET_free_non_null (mc->commit_links[k]); + } + GNUNET_free (mc); +} + +/* end of plugin_exchangedb_common.c */ diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c new file mode 100644 index 000000000..0395c208e --- /dev/null +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -0,0 +1,4295 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file plugin_exchangedb_postgres.c + * @brief Low-level (statement-level) Postgres database access for the exchange + * @author Florian Dold + * @author Christian Grothoff + * @author Sree Harsha Totakura + */ +#include "platform.h" +#include "taler_pq_lib.h" +#include "taler_exchangedb_plugin.h" +#include <pthread.h> +#include <libpq-fe.h> + +#include "plugin_exchangedb_common.c" + +/** + * For testing / experiments, we set the Postgres schema to + * #TALER_TEMP_SCHEMA_NAME so we can easily purge everything + * associated with a test. We *also* should use the database + * "talercheck" instead of "taler" for testing, but we're doing + * both: better safe than sorry. + */ +#define TALER_TEMP_SCHEMA_NAME "taler_temporary" + +/** + * Log a query error. + * + * @param result PQ result object of the query that failed + */ +#define QUERY_ERR(result) \ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result)) + + +/** + * Log a really unexpected PQ error. + * + * @param result PQ result object of the PQ operation that failed + */ +#define BREAK_DB_ERR(result) do { \ + GNUNET_break (0); \ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ + } while (0) + + +/** + * Shorthand for exit jumps. Logs the current line number + * and jumps to the "EXITIF_exit" label. + * + * @param cond condition that must be TRUE to exit with an error + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Execute an SQL statement and log errors on failure. Must be + * run in a function that has an "SQLEXEC_fail" label to jump + * to in case the SQL statement failed. + * + * @param conn database connection + * @param sql SQL statement to run + */ +#define SQLEXEC_(conn, sql) \ + do { \ + PGresult *result = PQexec (conn, sql); \ + if (PGRES_COMMAND_OK != PQresultStatus (result)) \ + { \ + BREAK_DB_ERR (result); \ + PQclear (result); \ + goto SQLEXEC_fail; \ + } \ + PQclear (result); \ + } while (0) + + +/** + * Run an SQL statement, ignoring errors and clearing the result. + * + * @param conn database connection + * @param sql SQL statement to run + */ +#define SQLEXEC_IGNORE_ERROR_(conn, sql) \ + do { \ + PGresult *result = PQexec (conn, sql); \ + PQclear (result); \ + } while (0) + + +/** + * Handle for a database session (per-thread, for transactions). + */ +struct TALER_EXCHANGEDB_Session +{ + /** + * Postgres connection handle. + */ + PGconn *conn; +}; + + +/** + * Type of the "cls" argument given to each of the functions in + * our API. + */ +struct PostgresClosure +{ + + /** + * Thread-local database connection. + * Contains a pointer to `PGconn` or NULL. + */ + pthread_key_t db_conn_threadlocal; + + /** + * Database connection string, as read from + * the configuration. + */ + char *connection_cfg_str; +}; + + + +/** + * Set the given connection to use a temporary schema + * + * @param db the database connection + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error + */ +static int +set_temporary_schema (PGconn *db) +{ + SQLEXEC_(db, + "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";" + "SET search_path to " TALER_TEMP_SCHEMA_NAME ";"); + return GNUNET_OK; + SQLEXEC_fail: + return GNUNET_SYSERR; +} + + +/** + * Drop the temporary taler schema. This is only useful for testcases + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database session to use + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static int +postgres_drop_temporary (void *cls, + struct TALER_EXCHANGEDB_Session *session) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Dropping temporary tables\n"); + SQLEXEC_ (session->conn, + "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;"); + return GNUNET_OK; + SQLEXEC_fail: + return GNUNET_SYSERR; +} + + +/** + * Function called by libpq whenever it wants to log something. + * We already log whenever we care, so this function does nothing + * and merely exists to silence the libpq logging. + * + * @param arg NULL + * @param res information about some libpq event + */ +static void +pq_notice_receiver_cb (void *arg, + const PGresult *res) +{ + /* do nothing, intentionally */ +} + + +/** + * Function called by libpq whenever it wants to log something. + * We log those using the Taler logger. + * + * @param arg NULL + * @param message information about some libpq event + */ +static void +pq_notice_processor_cb (void *arg, + const char *message) +{ + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, + "pq", + "%s", + message); +} + + +/** + * Create the necessary tables if they are not present + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param temporary should we use a temporary schema + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static int +postgres_create_tables (void *cls, + int temporary) +{ + struct PostgresClosure *pc = cls; + PGconn *conn; + + conn = PQconnectdb (pc->connection_cfg_str); + if (CONNECTION_OK != PQstatus (conn)) + { + TALER_LOG_ERROR ("Database connection failed: %s\n", + PQerrorMessage (conn)); + PQfinish (conn); + return GNUNET_SYSERR; + } + PQsetNoticeReceiver (conn, + &pq_notice_receiver_cb, + NULL); + PQsetNoticeProcessor (conn, + &pq_notice_processor_cb, + NULL); + if ( (GNUNET_YES == temporary) && + (GNUNET_SYSERR == set_temporary_schema (conn))) + { + PQfinish (conn); + return GNUNET_SYSERR; + } +#define SQLEXEC(sql) SQLEXEC_(conn, sql); +#define SQLEXEC_INDEX(sql) SQLEXEC_IGNORE_ERROR_(conn, sql); + /* Denomination table for holding the publicly available information of + denominations keys. The denominations are to be referred to by using + foreign keys. The denominations are deleted by a housekeeping tool; + hence, do not use `ON DELETE CASCADE' on these rows in the tables + referencing these rows */ + SQLEXEC ("CREATE TABLE IF NOT EXISTS denominations" + "(pub BYTEA PRIMARY KEY" + ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)" + ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" + ",valid_from INT8 NOT NULL" + ",expire_withdraw INT8 NOT NULL" + ",expire_spend INT8 NOT NULL" + ",expire_legal INT8 NOT NULL" + ",coin_val INT8 NOT NULL" /* value of this denom */ + ",coin_frac INT4 NOT NULL" /* fractional value of this denom */ + ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */ + ",fee_withdraw_val INT8 NOT NULL" + ",fee_withdraw_frac INT4 NOT NULL" + ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",fee_deposit_val INT8 NOT NULL" + ",fee_deposit_frac INT4 NOT NULL" + ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",fee_refresh_val INT8 NOT NULL" + ",fee_refresh_frac INT4 NOT NULL" + ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ")"); + /* reserves table is for summarization of a reserve. It is updated when new + funds are added and existing funds are withdrawn. The 'expiration_date' + can be used to eventually get rid of reserves that have not been used + for a very long time (either by refunding the owner or by greedily + grabbing the money, depending on the Exchange's terms of service) */ + SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves" + "(reserve_pub BYTEA PRIMARY KEY" + ",current_balance_val INT8 NOT NULL" + ",current_balance_frac INT4 NOT NULL" + ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",expiration_date INT8 NOT NULL" + ")"); + /* index on reserves table */ + SQLEXEC_INDEX ("CREATE INDEX reserves_reserve_pub_index ON " + "reserves (reserve_pub)"); + /* reserves_in table collects the transactions which transfer funds + into the reserve. The rows of this table correspond to each + incoming transaction. */ + SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in" + "(reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",balance_val INT8 NOT NULL" + ",balance_frac INT4 NOT NULL" + ",balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",details TEXT NOT NULL " + ",execution_date INT8 NOT NULL" + ",PRIMARY KEY (reserve_pub,details)" + ");"); + /* Create indices on reserves_in */ + SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_index" + " ON reserves_in (reserve_pub);"); + SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_details_index" + " ON reserves_in (reserve_pub,details);"); + SQLEXEC_INDEX ("CREATE INDEX execution_index" + " ON reserves_in (execution_date);"); + /* Table with the withdraw operations that have been performed on a reserve. + The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary + key, as (broken) clients that use a non-random coin and blinding factor + should fail to even withdraw, as otherwise the coins will fail to deposit + (as they really must be unique). */ + SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out" + "(h_blind_ev BYTEA PRIMARY KEY" + ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" + ",denom_sig BYTEA NOT NULL" + ",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)" + ",execution_date INT8 NOT NULL" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",withdraw_fee_val INT8 NOT NULL" + ",withdraw_fee_frac INT4 NOT NULL" + ",withdraw_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ");"); + /* Index blindcoins(reserve_pub) for get_reserves_out statement */ + SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON" + " reserves_out (reserve_pub)"); + SQLEXEC_INDEX ("CREATE INDEX reserves_out_h_blind_ev_index ON " + "reserves_out (h_blind_ev)"); + /* Table with coins that have been (partially) spent, used to track + coin information only once. */ + SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins " + "(coin_pub BYTEA NOT NULL PRIMARY KEY" + ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" + ",denom_sig BYTEA NOT NULL" + ")"); + /** + * The DB will show negative values for some values of the following fields as + * we use them as 16 bit unsigned integers + * @a num_oldcoins + * @a num_newcoins + * Do not do arithmetic in SQL on these fields. + * NOTE: maybe we should instead forbid values >= 2^15 categorically? + */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions " + "(session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)" + ",num_oldcoins INT2 NOT NULL" + ",num_newcoins INT2 NOT NULL" + ",noreveal_index INT2 NOT NULL" + ")"); + /* Table with coins that have been melted. Gives the coin's public + key (coin_pub), the melting session, the index of this coin in that + session, the signature affirming the melting and the amount that + this coin contributed to the melting session. + */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melts " + "(coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)" + ",session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)" + ",oldcoin_index INT2 NOT NULL" + ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",melt_fee_val INT8 NOT NULL" + ",melt_fee_frac INT4 NOT NULL" + ",melt_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",PRIMARY KEY (session_hash, oldcoin_index)" /* a coin can be used only + once in a refresh session */ + ") "); + /* Table with information about the desired denominations to be created + during a refresh operation; contains the denomination key for each + of the coins (for a given refresh session) */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order " + "(session_hash BYTEA NOT NULL CHECK (LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash)" + ",newcoin_index INT2 NOT NULL " + ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" + ",PRIMARY KEY (session_hash, newcoin_index)" + ")"); + + /* Table with the commitments for a refresh operation; includes + the session_hash for which this is the link information, the + oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1), + as well as the actual link data (the transfer public key and the encrypted + link secret). + NOTE: We might want to simplify this and not have the oldcoin_index + and instead store all link secrets, one after the other, in one big BYTEA. + (#3814) */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link " + "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)" + ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)" + ",link_secret_enc BYTEA NOT NULL" + ",oldcoin_index INT2 NOT NULL" + ",cnc_index INT2 NOT NULL" + ")"); + /* Table with the commitments for the new coins that are to be created + during a melting session. Includes the session, the cut-and-choose + index and the index of the new coin, and the envelope of the new + coin to be signed, as well as the encrypted information about the + private key and the blinding factor for the coin (for verification + in case this cnc_index is chosen to be revealed) + + NOTE: We might want to simplify this and not have the + newcoin_index and instead store all coin_evs and + link_vector_encs, one after the other, in two big BYTEAs. + (#3815) */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin " + "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) " + ",cnc_index INT2 NOT NULL" + ",newcoin_index INT2 NOT NULL" + ",link_vector_enc BYTEA NOT NULL" + ",coin_ev BYTEA NOT NULL" + ")"); + /* Table with the signatures over coins generated during a refresh + operation. Needed to answer /refresh/link queries later. Stores + the coin signatures under the respective session hash and index. */ + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_out " + "(session_hash BYTEA NOT NULL CHECK(LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash) " + ",newcoin_index INT2 NOT NULL" + ",ev_sig BYTEA NOT NULL" + ")"); + /* This table contains the wire transfers the exchange is supposed to + execute to transmit funds to the merchants (and manage refunds). */ + SQLEXEC("CREATE TABLE IF NOT EXISTS deposits " + "(serial_id BIGSERIAL PRIMARY KEY" + ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)" + ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" + ",denom_sig BYTEA NOT NULL" + ",transaction_id INT8 NOT NULL" + ",amount_with_fee_val INT8 NOT NULL" + ",amount_with_fee_frac INT4 NOT NULL" + ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",deposit_fee_val INT8 NOT NULL" + ",deposit_fee_frac INT4 NOT NULL" + ",deposit_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",timestamp INT8 NOT NULL" + ",refund_deadline INT8 NOT NULL" + ",wire_deadline INT8 NOT NULL" + ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" + ",h_contract BYTEA NOT NULL CHECK (LENGTH(h_contract)=64)" + ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)" + ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)" + ",wire TEXT NOT NULL" + ",tiny BOOLEAN NOT NULL DEFAULT false" + ",done BOOLEAN NOT NULL DEFAULT false" + ")"); + /* Index for get_deposit statement on coin_pub, transaction_id and merchant_pub */ + SQLEXEC_INDEX("CREATE INDEX deposits_coin_pub_index " + "ON deposits(coin_pub, transaction_id, merchant_pub)"); + /* Table for the tracking API, mapping from wire transfer identifiers + to transactions and back */ + SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking " + "(h_contract BYTEA CHECK (LENGTH(h_contract)=64)" + ",h_wire BYTEA CHECK (LENGTH(h_wire)=64)" + ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)" + ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" + ",transaction_id INT8 NOT NULL" + ",wtid_raw BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")" + ",execution_time INT8 NOT NULL" + ",coin_amount_val INT8 NOT NULL" + ",coin_amount_frac INT4 NOT NULL" + ",coin_amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ",coin_fee_val INT8 NOT NULL" + ",coin_fee_frac INT4 NOT NULL" + ",coin_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" + ")"); + /* Index for lookup_transactions statement on wtid */ + SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index " + "ON aggregation_tracking(wtid_raw)"); + /* Index for lookup_deposit_wtid statement */ + SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_deposit_index " + "ON aggregation_tracking(coin_pub,h_contract,h_wire,transaction_id,merchant_pub)"); + + /* This table contains the pre-commit data for + wire transfers the exchange is about to execute. */ + SQLEXEC("CREATE TABLE IF NOT EXISTS prewire " + "(serial_id BIGSERIAL PRIMARY KEY" + ",type TEXT NOT NULL" + ",finished BOOLEAN NOT NULL DEFAULT false" + ",buf BYTEA NOT NULL" + ")"); + /* Index for prepare_data_iterate statement */ + SQLEXEC_INDEX("CREATE INDEX prepare_iteration_index " + "ON prewire(type,finished)"); + + +#undef SQLEXEC +#undef SQLEXEC_INDEX + + PQfinish (conn); + return GNUNET_OK; + + SQLEXEC_fail: + PQfinish (conn); + return GNUNET_SYSERR; +} + + +/** + * Setup prepared statements. + * + * @param db_conn connection handle to initialize + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + */ +static int +postgres_prepare (PGconn *db_conn) +{ + PGresult *result; + +#define PREPARE(name, sql, ...) \ + do { \ + result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ + if (PGRES_COMMAND_OK != PQresultStatus (result)) \ + { \ + BREAK_DB_ERR (result); \ + PQclear (result); result = NULL; \ + return GNUNET_SYSERR; \ + } \ + PQclear (result); result = NULL; \ + } while (0); + + /* Used in #postgres_insert_denomination_info() */ + PREPARE ("denomination_insert", + "INSERT INTO denominations " + "(pub" + ",master_pub" + ",master_sig" + ",valid_from" + ",expire_withdraw" + ",expire_spend" + ",expire_legal" + ",coin_val" /* value of this denom */ + ",coin_frac" /* fractional value of this denom */ + ",coin_curr" /* assuming same currency for fees */ + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" /* must match coin_curr */ + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" /* must match coin_curr */ + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" /* must match coin_curr */ + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," + " $11, $12, $13, $14, $15, $16, $17, $18, $19);", + 19, NULL); + + /* Used in #postgres_get_denomination_info() */ + PREPARE ("denomination_get", + "SELECT" + " master_pub" + ",master_sig" + ",valid_from" + ",expire_withdraw" + ",expire_spend" + ",expire_legal" + ",coin_val" /* value of this denom */ + ",coin_frac" /* fractional value of this denom */ + ",coin_curr" /* assuming same currency for fees */ + ",fee_withdraw_val" + ",fee_withdraw_frac" + ",fee_withdraw_curr" /* must match coin_curr */ + ",fee_deposit_val" + ",fee_deposit_frac" + ",fee_deposit_curr" /* must match coin_curr */ + ",fee_refresh_val" + ",fee_refresh_frac" + ",fee_refresh_curr" /* must match coin_curr */ + " FROM denominations" + " WHERE pub=$1;", + 1, NULL); + + /* Used in #postgres_reserve_get() */ + PREPARE ("reserve_get", + "SELECT" + " current_balance_val" + ",current_balance_frac" + ",current_balance_curr" + ",expiration_date" + " FROM reserves" + " WHERE reserve_pub=$1" + " LIMIT 1;", + 1, NULL); + + /* Used in #postgres_reserves_in_insert() when the reserve is new */ + PREPARE ("reserve_create", + "INSERT INTO reserves " + "(reserve_pub" + ",current_balance_val" + ",current_balance_frac" + ",current_balance_curr" + ",expiration_date" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5, NULL); + + /* Used in #postgres_reserves_update() when the reserve is updated */ + PREPARE ("reserve_update", + "UPDATE reserves" + " SET" + " expiration_date=$1 " + ",current_balance_val=$2 " + ",current_balance_frac=$3 " + "WHERE current_balance_curr=$4 AND reserve_pub=$5", + 5, NULL); + + /* Used in #postgres_reserves_in_insert() to store transaction details */ + PREPARE ("reserves_in_add_transaction", + "INSERT INTO reserves_in " + "(reserve_pub" + ",balance_val" + ",balance_frac" + ",balance_curr" + ",details" + ",execution_date" + ") VALUES " + "($1, $2, $3, $4, $5, $6);", + 6, NULL); + + /* Used in #postgres_get_reserve_history() to obtain inbound transactions + for a reserve */ + PREPARE ("reserves_in_get_transactions", + "SELECT" + " balance_val" + ",balance_frac" + ",balance_curr" + ",execution_date" + ",details" + " FROM reserves_in" + " WHERE reserve_pub=$1", + 1, NULL); + + /* Used in #postgres_insert_withdraw_info() to store + the signature of a blinded coin with the blinded coin's + details before returning it during /reserve/withdraw. We store + the coin's denomination information (public key, signature) + and the blinded message as well as the reserve that the coin + is being withdrawn from and the signature of the message + authorizing the withdrawal. */ + PREPARE ("insert_withdraw_info", + "INSERT INTO reserves_out " + "(h_blind_ev" + ",denom_pub" + ",denom_sig" + ",reserve_pub" + ",reserve_sig" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",withdraw_fee_val" + ",withdraw_fee_frac" + ",withdraw_fee_curr" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);", + 12, NULL); + + /* Used in #postgres_get_withdraw_info() to + locate the response for a /reserve/withdraw request + using the hash of the blinded message. Used to + make sure /reserve/withdraw requests are idempotent. */ + PREPARE ("get_withdraw_info", + "SELECT" + " denom_pub" + ",denom_sig" + ",reserve_sig" + ",reserve_pub" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",withdraw_fee_val" + ",withdraw_fee_frac" + ",withdraw_fee_curr" + " FROM reserves_out" + " WHERE h_blind_ev=$1", + 1, NULL); + + /* Used during #postgres_get_reserve_history() to + obtain all of the /reserve/withdraw operations that + have been performed on a given reserve. (i.e. to + demonstrate double-spending) */ + PREPARE ("get_reserves_out", + "SELECT" + " h_blind_ev" + ",denom_pub" + ",denom_sig" + ",reserve_sig" + ",execution_date" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",withdraw_fee_val" + ",withdraw_fee_frac" + ",withdraw_fee_curr" + " FROM reserves_out" + " WHERE reserve_pub=$1;", + 1, NULL); + + /* Used in #postgres_get_refresh_session() to fetch + high-level information about a refresh session */ + PREPARE ("get_refresh_session", + "SELECT" + " num_oldcoins" + ",num_newcoins" + ",noreveal_index" + " FROM refresh_sessions " + " WHERE session_hash=$1 ", + 1, NULL); + + /* Used in #postgres_create_refresh_session() to store + high-level information about a refresh session */ + PREPARE ("insert_refresh_session", + "INSERT INTO refresh_sessions " + "(session_hash " + ",num_oldcoins " + ",num_newcoins " + ",noreveal_index " + ") VALUES " + "($1, $2, $3, $4);", + 4, NULL); + + /* Used in #postgres_get_known_coin() to fetch + the denomination public key and signature for + a coin known to the exchange. */ + PREPARE ("get_known_coin", + "SELECT" + " denom_pub" + ",denom_sig" + " FROM known_coins" + " WHERE coin_pub=$1", + 1, NULL); + + /* Used in #postgres_insert_known_coin() to store + the denomination public key and signature for + a coin known to the exchange. */ + PREPARE ("insert_known_coin", + "INSERT INTO known_coins " + "(coin_pub" + ",denom_pub" + ",denom_sig" + ") VALUES " + "($1,$2,$3);", + 3, NULL); + + /* Store information about the desired denominations for a + refresh operation, used in #postgres_insert_refresh_order() */ + PREPARE ("insert_refresh_order", + "INSERT INTO refresh_order " + "(newcoin_index " + ",session_hash " + ",denom_pub " + ") VALUES " + "($1, $2, $3);", + 3, NULL); + + /* Obtain information about the desired denominations for a + refresh operation, used in #postgres_get_refresh_order() */ + PREPARE ("get_refresh_order", + "SELECT denom_pub" + " FROM refresh_order" + " WHERE session_hash=$1 AND newcoin_index=$2", + 2, NULL); + + /* Used in #postgres_insert_refresh_melt to store information + about melted coins */ + PREPARE ("insert_refresh_melt", + "INSERT INTO refresh_melts " + "(coin_pub " + ",session_hash" + ",oldcoin_index " + ",coin_sig " + ",amount_with_fee_val " + ",amount_with_fee_frac " + ",amount_with_fee_curr " + ",melt_fee_val " + ",melt_fee_frac " + ",melt_fee_curr " + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", + 10, NULL); + + /* Used in #postgres_get_refresh_melt to obtain information + about melted coins */ + PREPARE ("get_refresh_melt", + "SELECT" + " coin_pub" + ",coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",melt_fee_val " + ",melt_fee_frac " + ",melt_fee_curr " + " FROM refresh_melts" + " WHERE session_hash=$1 AND oldcoin_index=$2", + 2, NULL); + + /* Query the 'refresh_melts' by coin public key */ + PREPARE ("get_refresh_melt_by_coin", + "SELECT" + " session_hash" + /* ",oldcoin_index" // not needed */ + ",coin_sig" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",melt_fee_val " + ",melt_fee_frac " + ",melt_fee_curr " + " FROM refresh_melts" + " WHERE coin_pub=$1", + 1, NULL); + + /* Used in #postgres_insert_refresh_commit_links() to + store commitments */ + PREPARE ("insert_refresh_commit_link", + "INSERT INTO refresh_commit_link " + "(session_hash" + ",transfer_pub" + ",cnc_index" + ",oldcoin_index" + ",link_secret_enc" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5, NULL); + + /* Used in #postgres_get_refresh_commit_links() to + retrieve original commitments during /refresh/reveal */ + PREPARE ("get_refresh_commit_link", + "SELECT" + " transfer_pub" + ",link_secret_enc" + " FROM refresh_commit_link" + " WHERE session_hash=$1 AND cnc_index=$2 AND oldcoin_index=$3", + 3, NULL); + + /* Used in #postgres_insert_refresh_commit_coins() to + store coin commitments. */ + PREPARE ("insert_refresh_commit_coin", + "INSERT INTO refresh_commit_coin " + "(session_hash" + ",cnc_index" + ",newcoin_index" + ",link_vector_enc" + ",coin_ev" + ") VALUES " + "($1, $2, $3, $4, $5);", + 5, NULL); + + /* Used in #postgres_get_refresh_commit_coins() to + retrieve the original coin envelopes, to either be + verified or signed. */ + PREPARE ("get_refresh_commit_coin", + "SELECT" + " link_vector_enc" + ",coin_ev" + " FROM refresh_commit_coin" + " WHERE session_hash=$1 AND cnc_index=$2 AND newcoin_index=$3", + 3, NULL); + + /* Store information about a /deposit the exchange is to execute. + Used in #postgres_insert_deposit(). */ + PREPARE ("insert_deposit", + "INSERT INTO deposits " + "(coin_pub" + ",denom_pub" + ",denom_sig" + ",transaction_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",deposit_fee_val" + ",deposit_fee_frac" + ",deposit_fee_curr" + ",timestamp" + ",refund_deadline" + ",wire_deadline" + ",merchant_pub" + ",h_contract" + ",h_wire" + ",coin_sig" + ",wire" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," + " $11, $12, $13, $14, $15, $16, $17, $18);", + 18, NULL); + + /* Fetch an existing deposit request, used to ensure idempotency + during /deposit processing. Used in #postgres_have_deposit(). */ + PREPARE ("get_deposit", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",timestamp" + ",refund_deadline" + ",wire_deadline" + ",h_contract" + ",h_wire" + " FROM deposits" + " WHERE (" + " (coin_pub=$1) AND" + " (transaction_id=$2) AND" + " (merchant_pub=$3)" + " )", + 3, NULL); + + /* Fetch an existing deposit request. + Used in #postgres_wire_lookup_deposit_wtid(). */ + PREPARE ("get_deposit_for_wtid", + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",deposit_fee_val" + ",deposit_fee_frac" + ",deposit_fee_curr" + ",wire_deadline" + " FROM deposits" + " WHERE (" + " (coin_pub=$1) AND" + " (transaction_id=$2) AND" + " (merchant_pub=$3) AND" + " (h_contract=$4) AND" + " (h_wire=$5)" + " )", + 5, NULL); + + /* Used in #postgres_get_ready_deposit() */ + PREPARE ("deposits_get_ready", + "SELECT" + " serial_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",deposit_fee_val" + ",deposit_fee_frac" + ",deposit_fee_curr" + ",wire_deadline" + ",transaction_id" + ",h_contract" + ",wire" + ",merchant_pub" + ",coin_pub" + " FROM deposits" + " WHERE" + " tiny=false AND" + " done=false" + " ORDER BY wire_deadline ASC" + " LIMIT 1;", + 0, NULL); + + /* Used in #postgres_iterate_matching_deposits() */ + PREPARE ("deposits_iterate_matching", + "SELECT" + " serial_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",deposit_fee_val" + ",deposit_fee_frac" + ",deposit_fee_curr" + ",wire_deadline" + ",transaction_id" + ",h_contract" + ",coin_pub" + " FROM deposits" + " WHERE" + " merchant_pub=$1 AND" + " h_wire=$2 AND" + " done=false" + " ORDER BY wire_deadline ASC" + " LIMIT $3", + 3, NULL); + + /* Used in #postgres_mark_deposit_tiny() */ + PREPARE ("mark_deposit_tiny", + "UPDATE deposits" + " SET tiny=true" + " WHERE serial_id=$1", + 1, NULL); + + /* Used in #postgres_mark_deposit_done() */ + PREPARE ("mark_deposit_done", + "UPDATE deposits" + " SET done=true" + " WHERE serial_id=$1", + 1, NULL); + + /* Used in #postgres_get_coin_transactions() to obtain information + about how a coin has been spend with /deposit requests. */ + PREPARE ("get_deposit_with_coin_pub", + "SELECT" + " denom_pub" + ",denom_sig" + ",transaction_id" + ",amount_with_fee_val" + ",amount_with_fee_frac" + ",amount_with_fee_curr" + ",deposit_fee_val" + ",deposit_fee_frac" + ",deposit_fee_curr" + ",timestamp" + ",refund_deadline" + ",merchant_pub" + ",h_contract" + ",h_wire" + ",wire" + ",coin_sig" + " FROM deposits" + " WHERE coin_pub=$1", + 1, NULL); + + /* Used in #postgres_insert_refresh_out() to store the + generated signature(s) for future requests, i.e. /refresh/link */ + PREPARE ("insert_refresh_out", + "INSERT INTO refresh_out " + "(session_hash" + ",newcoin_index" + ",ev_sig" + ") VALUES " + "($1, $2, $3)", + 3, NULL); + + /* Used in #postgres_get_link_data_list(). We use the session_hash + to obtain the "noreveal_index" for that session, and then select + the encrypted link vectors (link_vector_enc) and the + corresponding signatures (ev_sig) and the denomination keys from + the respective tables (namely refresh_melts and refresh_order) + using the session_hash as the primary filter (on join) and the + 'noreveal_index' to constrain the selection on the commitment. + We also want to get the triplet for each of the newcoins, so we + have another constraint to ensure we get each triplet with + matching "newcoin_index" values. NOTE: This may return many + results, both for different sessions and for the different coins + being exchangeed in the refresh ops. NOTE: There may be more + efficient ways to express the same query. */ + PREPARE ("get_link", + "SELECT link_vector_enc,ev_sig,ro.denom_pub" + " FROM refresh_melts rm " + " JOIN refresh_order ro USING (session_hash)" + " JOIN refresh_commit_coin rcc USING (session_hash)" + " JOIN refresh_sessions rs USING (session_hash)" + " JOIN refresh_out rc USING (session_hash)" + " WHERE ro.session_hash=$1" + " AND ro.newcoin_index=rcc.newcoin_index" + " AND ro.newcoin_index=rc.newcoin_index" + " AND rcc.cnc_index=rs.noreveal_index", + 1, NULL); + + /* Used in #postgres_get_transfer(). Given the public key of a + melted coin, we obtain the corresponding encrypted link secret + and the transfer public key. This is done by first finding + the session_hash(es) of all sessions the coin was melted into, + and then constraining the result to the selected "noreveal_index" + and the transfer public key to the corresponding index of the + old coin. + NOTE: This may (in theory) return multiple results, one per session + that the old coin was melted into. */ + PREPARE ("get_transfer", + "SELECT transfer_pub,link_secret_enc,session_hash" + " FROM refresh_melts rm" + " JOIN refresh_commit_link rcl USING (session_hash)" + " JOIN refresh_sessions rs USING (session_hash)" + " WHERE rm.coin_pub=$1" + " AND rm.oldcoin_index = rcl.oldcoin_index" + " AND rcl.cnc_index=rs.noreveal_index", + 1, NULL); + + /* Used in #postgres_lookup_wire_transfer */ + PREPARE ("lookup_transactions", + "SELECT" + " h_contract" + ",h_wire" + ",coin_pub" + ",merchant_pub" + ",transaction_id" + ",execution_time" + ",coin_amount_val" + ",coin_amount_frac" + ",coin_amount_curr" + ",coin_fee_val" + ",coin_fee_frac" + ",coin_fee_curr" + " FROM aggregation_tracking" + " WHERE wtid_raw=$1", + 1, NULL); + + /* Used in #postgres_wire_lookup_deposit_wtid */ + PREPARE ("lookup_deposit_wtid", + "SELECT" + " wtid_raw" + ",execution_time" + ",coin_amount_val" + ",coin_amount_frac" + ",coin_amount_curr" + ",coin_fee_val" + ",coin_fee_frac" + ",coin_fee_curr" + " FROM aggregation_tracking" + " WHERE" + " coin_pub=$1 AND" + " h_contract=$2 AND" + " h_wire=$3 AND" + " transaction_id=$4 AND" + " merchant_pub=$5", + 5, NULL); + + /* Used in #postgres_insert_aggregation_tracking */ + PREPARE ("insert_aggregation_tracking", + "INSERT INTO aggregation_tracking " + "(h_contract" + ",h_wire" + ",coin_pub" + ",merchant_pub" + ",transaction_id" + ",wtid_raw" + ",execution_time" + ",coin_amount_val" + ",coin_amount_frac" + ",coin_amount_curr" + ",coin_fee_val" + ",coin_fee_frac" + ",coin_fee_curr" + ") VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + 13, NULL); + + + /* Used in #postgres_wire_prepare_data_insert() to store + wire transfer information before actually committing it with the bank */ + PREPARE ("wire_prepare_data_insert", + "INSERT INTO prewire " + "(type" + ",buf" + ") VALUES " + "($1, $2)", + 2, NULL); + + /* Used in #postgres_wire_prepare_data_mark_finished() */ + PREPARE ("wire_prepare_data_mark_done", + "UPDATE prewire" + " SET finished=true" + " WHERE serial_id=$1", + 1, NULL); + + /* Used in #postgres_wire_prepare_data_get() */ + PREPARE ("wire_prepare_data_get", + "SELECT" + " serial_id" + ",buf" + " FROM prewire" + " WHERE" + " type=$1 AND" + " finished=false" + " ORDER BY serial_id ASC" + " LIMIT 1", + 1, NULL); + + return GNUNET_OK; +#undef PREPARE +} + + +/** + * Close thread-local database connection when a thread is destroyed. + * + * @param cls closure we get from pthreads (the db handle) + */ +static void +db_conn_destroy (void *cls) +{ + struct TALER_EXCHANGEDB_Session *session = cls; + PGconn *db_conn = session->conn; + + if (NULL != db_conn) + PQfinish (db_conn); + GNUNET_free (session); +} + + +/** + * Get the thread-local database-handle. + * Connect to the db if the connection does not exist yet. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the + * database default one + * @return the database connection, or NULL on error + */ +static struct TALER_EXCHANGEDB_Session * +postgres_get_session (void *cls, + int temporary) +{ + struct PostgresClosure *pc = cls; + PGconn *db_conn; + struct TALER_EXCHANGEDB_Session *session; + + if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal))) + return session; + db_conn = PQconnectdb (pc->connection_cfg_str); + if (CONNECTION_OK != + PQstatus (db_conn)) + { + TALER_LOG_ERROR ("Database connection failed: %s\n", + PQerrorMessage (db_conn)); + GNUNET_break (0); + return NULL; + } + PQsetNoticeReceiver (db_conn, + &pq_notice_receiver_cb, + NULL); + PQsetNoticeProcessor (db_conn, + &pq_notice_processor_cb, + NULL); + if ( (GNUNET_YES == temporary) && + (GNUNET_SYSERR == set_temporary_schema(db_conn)) ) + { + GNUNET_break (0); + return NULL; + } + if (GNUNET_OK != + postgres_prepare (db_conn)) + { + GNUNET_break (0); + return NULL; + } + session = GNUNET_new (struct TALER_EXCHANGEDB_Session); + session->conn = db_conn; + if (0 != pthread_setspecific (pc->db_conn_threadlocal, + session)) + { + GNUNET_break (0); + PQfinish (db_conn); + GNUNET_free (session); + return NULL; + } + return session; +} + + +/** + * Start a transaction. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + * @return #GNUNET_OK on success + */ +static int +postgres_start (void *cls, + struct TALER_EXCHANGEDB_Session *session) +{ + PGresult *result; + + result = PQexec (session->conn, + "BEGIN"); + if (PGRES_COMMAND_OK != + PQresultStatus (result)) + { + TALER_LOG_ERROR ("Failed to start transaction: %s\n", + PQresultErrorMessage (result)); + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + + PQclear (result); + return GNUNET_OK; +} + + +/** + * Roll back the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + * @return #GNUNET_OK on success + */ +static void +postgres_rollback (void *cls, + struct TALER_EXCHANGEDB_Session *session) +{ + PGresult *result; + + result = PQexec (session->conn, + "ROLLBACK"); + GNUNET_break (PGRES_COMMAND_OK == + PQresultStatus (result)); + PQclear (result); +} + + +/** + * Commit the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + * @return #GNUNET_OK on success + */ +static int +postgres_commit (void *cls, + struct TALER_EXCHANGEDB_Session *session) +{ + PGresult *result; + + result = PQexec (session->conn, + "COMMIT"); + if (PGRES_COMMAND_OK != + PQresultStatus (result)) + { + const char *sqlstate; + + sqlstate = PQresultErrorField (result, + PG_DIAG_SQLSTATE); + if (NULL == sqlstate) + { + /* very unexpected... */ + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + /* 40P01: deadlock, 40001: serialization failure */ + if ( (0 == strcmp (sqlstate, + "40P01")) || + (0 == strcmp (sqlstate, + "40001")) ) + { + /* These two can be retried and have a fair chance of working + the next time */ + PQclear (result); + return GNUNET_NO; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database commit failure: %s\n", + sqlstate); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Insert a denomination key's public information into the database for + * reference by auditors and other consistency checks. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param denom_pub the public key used for signing coins of this denomination + * @param issue issuing information with value, fees and other info about the coin + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ +static int +postgres_insert_denomination_info (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue) +{ + PGresult *result; + int ret; + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key), + GNUNET_PQ_query_param_auto_from_type (&issue->properties.master), + GNUNET_PQ_query_param_auto_from_type (&issue->signature), + GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.start), + GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_withdraw), + GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_spend), + GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_legal), + TALER_PQ_query_param_amount_nbo (&issue->properties.value), + TALER_PQ_query_param_amount_nbo (&issue->properties.fee_withdraw), + TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit), + TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh), + GNUNET_PQ_query_param_end + }; + /* check fees match coin currency */ + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->properties.value, + &issue->properties.fee_withdraw)); + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->properties.value, + &issue->properties.fee_deposit)); + GNUNET_assert (GNUNET_YES == + TALER_amount_cmp_currency_nbo (&issue->properties.value, + &issue->properties.fee_refresh)); + + result = GNUNET_PQ_exec_prepared (session->conn, + "denomination_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ret = GNUNET_SYSERR; + BREAK_DB_ERR (result); + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; +} + + +/** + * Fetch information about a denomination key. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param denom_pub the public key used for signing coins of this denomination + * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL + * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure + */ +static int +postgres_get_denomination_info (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_DenominationPublicKey *denom_pub, + struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "denomination_get", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + if (1 != PQntuples (result)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + if (NULL == issue) + { + PQclear (result); + return GNUNET_OK; + } + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("master_pub", + &issue->properties.master), + GNUNET_PQ_result_spec_auto_from_type ("master_sig", + &issue->signature), + GNUNET_PQ_result_spec_absolute_time_nbo ("valid_from", + &issue->properties.start), + GNUNET_PQ_result_spec_absolute_time_nbo ("expire_withdraw", + &issue->properties.expire_withdraw), + GNUNET_PQ_result_spec_absolute_time_nbo ("expire_spend", + &issue->properties.expire_spend), + GNUNET_PQ_result_spec_absolute_time_nbo ("expire_legal", + &issue->properties.expire_legal), + TALER_PQ_result_spec_amount_nbo ("coin", + &issue->properties.value), + TALER_PQ_result_spec_amount_nbo ("fee_withdraw", + &issue->properties.fee_withdraw), + TALER_PQ_result_spec_amount_nbo ("fee_deposit", + &issue->properties.fee_deposit), + TALER_PQ_result_spec_amount_nbo ("fee_refresh", + &issue->properties.fee_refresh), + GNUNET_PQ_result_spec_end + }; + + EXITIF (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + 0)); + } + PQclear (result); + return GNUNET_OK; + + EXITIF_exit: + PQclear (result); + return GNUNET_SYSERR; +} + + +/** + * Get the summary of a reserve. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection handle + * @param[in,out] reserve the reserve data. The public key of the reserve should be + * set in this structure; it is used to query the database. The balance + * and expiration are then filled accordingly. + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static int +postgres_reserve_get (void *cls, + struct TALER_EXCHANGEDB_Session *session, + struct TALER_EXCHANGEDB_Reserve *reserve) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type(&reserve->pub), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "reserve_get", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + { + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount("current_balance", &reserve->balance), + GNUNET_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry), + GNUNET_PQ_result_spec_end + }; + + EXITIF (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + 0)); + } + PQclear (result); + return GNUNET_OK; + + EXITIF_exit: + PQclear (result); + return GNUNET_SYSERR; +} + + +/** + * Updates a reserve with the data from the given reserve structure. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + * @param reserve the reserve structure whose data will be used to update the + * corresponding record in the database. + * @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error + */ +static int +reserves_update (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_Reserve *reserve) +{ + PGresult *result; + int ret; + + if (NULL == reserve) + return GNUNET_SYSERR; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&reserve->expiry), + TALER_PQ_query_param_amount (&reserve->balance), + GNUNET_PQ_query_param_auto_from_type (&reserve->pub), + GNUNET_PQ_query_param_end + }; + result = GNUNET_PQ_exec_prepared (session->conn, + "reserve_update", + params); + if (PGRES_COMMAND_OK != PQresultStatus(result)) + { + QUERY_ERR (result); + ret = GNUNET_SYSERR; + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; +} + + +/** + * Insert an incoming transaction into reserves. New reserves are also created + * through this function. Note that this API call starts (and stops) its + * own transaction scope (so the application must not do so). + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection handle + * @param reserve_pub public key of the reserve + * @param balance the amount that has to be added to the reserve + * @param execution_time when was the amount added + * @param details bank transaction details justifying the increment, + * must be unique for each incoming transaction + * @return #GNUNET_OK upon success; #GNUNET_NO if the given + * @a details are already known for this @a reserve_pub, + * #GNUNET_SYSERR upon failures (DB error, incompatible currency) + */ +static int +postgres_reserves_in_insert (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *balance, + struct GNUNET_TIME_Absolute execution_time, + const json_t *details) +{ + PGresult *result; + int reserve_exists; + struct TALER_EXCHANGEDB_Reserve reserve; + struct GNUNET_TIME_Absolute expiry; + + if (GNUNET_OK != postgres_start (cls, + session)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + reserve.pub = *reserve_pub; + reserve_exists = postgres_reserve_get (cls, + session, + &reserve); + if (GNUNET_SYSERR == reserve_exists) + { + GNUNET_break (0); + goto rollback; + } + expiry = GNUNET_TIME_absolute_add (execution_time, + TALER_IDLE_RESERVE_EXPIRATION_TIME); + if (GNUNET_NO == reserve_exists) + { + /* New reserve, create balance for the first time; we do this + before adding the actual transaction to "reserves_in", as + for a new reserve it can't be a duplicate 'add' operation, + and as the 'add' operation may need the reserve entry + as a foreign key. */ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + TALER_PQ_query_param_amount (balance), + GNUNET_PQ_query_param_absolute_time (&expiry), + GNUNET_PQ_query_param_end + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reserve does not exist; creating a new one\n"); + result = GNUNET_PQ_exec_prepared (session->conn, + "reserve_create", + params); + if (PGRES_COMMAND_OK != PQresultStatus(result)) + { + QUERY_ERR (result); + PQclear (result); + goto rollback; + } + PQclear (result); + } + /* Create new incoming transaction, SQL "primary key" logic + is used to guard against duplicates. If a duplicate is + detected, we rollback (which really shouldn't undo + anything) and return #GNUNET_NO to indicate that this failure + is kind-of harmless (already executed). */ + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&reserve.pub), + TALER_PQ_query_param_amount (balance), + TALER_PQ_query_param_json (details), + GNUNET_PQ_query_param_absolute_time (&execution_time), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "reserves_in_add_transaction", + params); + } + if (PGRES_COMMAND_OK != PQresultStatus(result)) + { + const char *efield; + + efield = PQresultErrorField (result, + PG_DIAG_SQLSTATE); + if ( (PGRES_FATAL_ERROR == PQresultStatus(result)) && + (NULL != strstr ("23505", /* unique violation */ + efield)) ) + { + /* This means we had the same reserve/justification/details + before */ + PQclear (result); + postgres_rollback (cls, + session); + return GNUNET_NO; + } + QUERY_ERR (result); + PQclear (result); + goto rollback; + } + PQclear (result); + + if (GNUNET_YES == reserve_exists) + { + /* If the reserve already existed, we need to still update the + balance; we do this after checking for duplication, as + otherwise we might have to actually pay the cost to roll this + back for duplicate transactions; like this, we should virtually + never actually have to rollback anything. */ + struct TALER_EXCHANGEDB_Reserve updated_reserve; + + updated_reserve.pub = reserve.pub; + if (GNUNET_OK != + TALER_amount_add (&updated_reserve.balance, + &reserve.balance, + balance)) + { + /* currency overflow or incompatible currency */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Attempt to deposit incompatible amount into reserve\n"); + goto rollback; + } + updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, + reserve.expiry); + if (GNUNET_OK != reserves_update (cls, + session, + &updated_reserve)) + goto rollback; + } + if (GNUNET_OK != postgres_commit (cls, + session)) + return GNUNET_SYSERR; + return GNUNET_OK; + + rollback: + postgres_rollback (cls, + session); + return GNUNET_SYSERR; +} + + +/** + * Locate the response for a /reserve/withdraw request under the + * key of the hash of the blinded message. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param h_blind hash of the blinded coin to be signed (will match + * `h_coin_envelope` in the @a collectable to be returned) + * @param collectable corresponding collectable coin (blind signature) + * if a coin is found + * @return #GNUNET_SYSERR on internal error + * #GNUNET_NO if the collectable was not found + * #GNUNET_YES on success + */ +static int +postgres_get_withdraw_info (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_blind, + struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_blind), + GNUNET_PQ_query_param_end + }; + int ret; + + ret = GNUNET_SYSERR; + result = GNUNET_PQ_exec_prepared (session->conn, + "get_withdraw_info", + params); + + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + goto cleanup; + } + if (0 == PQntuples (result)) + { + ret = GNUNET_NO; + goto cleanup; + } + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &collectable->denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &collectable->sig.rsa_signature), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &collectable->reserve_sig), + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &collectable->reserve_pub), + TALER_PQ_result_spec_amount ("amount_with_fee", + &collectable->amount_with_fee), + TALER_PQ_result_spec_amount ("withdraw_fee", + &collectable->withdraw_fee), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + goto cleanup; + } + } + collectable->h_coin_envelope = *h_blind; + ret = GNUNET_YES; + + cleanup: + PQclear (result); + return ret; +} + + +/** + * Store collectable bit coin under the corresponding + * hash of the blinded message. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param collectable corresponding collectable coin (blind signature) + * if a coin is found + * @return #GNUNET_SYSERR on internal error + * #GNUNET_NO if the collectable was not found + * #GNUNET_YES on success + */ +static int +postgres_insert_withdraw_info (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable) +{ + PGresult *result; + struct TALER_EXCHANGEDB_Reserve reserve; + int ret = GNUNET_SYSERR; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute expiry; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope), + GNUNET_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key), + GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature), + GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub), + GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig), + GNUNET_PQ_query_param_absolute_time (&now), + TALER_PQ_query_param_amount (&collectable->amount_with_fee), + TALER_PQ_query_param_amount (&collectable->withdraw_fee), + GNUNET_PQ_query_param_end + }; + + now = GNUNET_TIME_absolute_get (); + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_withdraw_info", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + goto cleanup; + } + reserve.pub = collectable->reserve_pub; + if (GNUNET_OK != postgres_reserve_get (cls, + session, + &reserve)) + { + /* Should have been checked before we got here... */ + GNUNET_break (0); + goto cleanup; + } + if (GNUNET_SYSERR == + TALER_amount_subtract (&reserve.balance, + &reserve.balance, + &collectable->amount_with_fee)) + { + /* Should have been checked before we got here... */ + GNUNET_break (0); + goto cleanup; + } + expiry = GNUNET_TIME_absolute_add (now, + TALER_IDLE_RESERVE_EXPIRATION_TIME); + reserve.expiry = GNUNET_TIME_absolute_max (expiry, + reserve.expiry); + if (GNUNET_OK != reserves_update (cls, + session, + &reserve)) + { + GNUNET_break (0); + goto cleanup; + } + ret = GNUNET_OK; + cleanup: + PQclear (result); + return ret; +} + + +/** + * Get all of the transaction history associated with the specified + * reserve. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session connection to use + * @param reserve_pub public key of the reserve + * @return known transaction history (NULL if reserve is unknown) + */ +static struct TALER_EXCHANGEDB_ReserveHistory * +postgres_get_reserve_history (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + PGresult *result; + struct TALER_EXCHANGEDB_ReserveHistory *rh; + struct TALER_EXCHANGEDB_ReserveHistory *rh_tail; + int rows; + int ret; + + rh = NULL; + rh_tail = NULL; + ret = GNUNET_SYSERR; + { + struct TALER_EXCHANGEDB_BankTransfer *bt; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "reserves_in_get_transactions", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + goto cleanup; + } + if (0 == (rows = PQntuples (result))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Asked to fetch history for an unknown reserve.\n"); + goto cleanup; + } + while (0 < rows) + { + bt = GNUNET_new (struct TALER_EXCHANGEDB_BankTransfer); + { + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("balance", + &bt->amount), + GNUNET_PQ_result_spec_absolute_time ("execution_date", + &bt->execution_date), + TALER_PQ_result_spec_json ("details", + &bt->wire), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_YES != + GNUNET_PQ_extract_result (result, rs, --rows)) + { + GNUNET_break (0); + GNUNET_free (bt); + PQclear (result); + goto cleanup; + } + } + bt->reserve_pub = *reserve_pub; + if (NULL != rh_tail) + { + rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory); + rh_tail = rh_tail->next; + } + else + { + rh_tail = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory); + rh = rh_tail; + } + rh_tail->type = TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE; + rh_tail->details.bank = bt; + } + PQclear (result); + } + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserve_pub), + GNUNET_PQ_query_param_end + }; + + GNUNET_assert (NULL != rh); + GNUNET_assert (NULL != rh_tail); + GNUNET_assert (NULL == rh_tail->next); + result = GNUNET_PQ_exec_prepared (session->conn, + "get_reserves_out", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + PQclear (result); + goto cleanup; + } + rows = PQntuples (result); + while (0 < rows) + { + struct TALER_EXCHANGEDB_CollectableBlindcoin *cbc; + + cbc = GNUNET_new (struct TALER_EXCHANGEDB_CollectableBlindcoin); + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev", + &cbc->h_coin_envelope), + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &cbc->denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &cbc->sig.rsa_signature), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &cbc->reserve_sig), + TALER_PQ_result_spec_amount ("amount_with_fee", + &cbc->amount_with_fee), + TALER_PQ_result_spec_amount ("withdraw_fee", + &cbc->withdraw_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_YES != + GNUNET_PQ_extract_result (result, rs, --rows)) + { + GNUNET_break (0); + GNUNET_free (cbc); + PQclear (result); + goto cleanup; + } + cbc->reserve_pub = *reserve_pub; + } + rh_tail->next = GNUNET_new (struct TALER_EXCHANGEDB_ReserveHistory); + rh_tail = rh_tail->next; + rh_tail->type = TALER_EXCHANGEDB_RO_WITHDRAW_COIN; + rh_tail->details.withdraw = cbc; + } + ret = GNUNET_OK; + PQclear (result); + } + cleanup: + if (GNUNET_SYSERR == ret) + { + common_free_reserve_history (cls, + rh); + rh = NULL; + } + return rh; +} + + +/** + * Check if we have the specified deposit already in the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param deposit deposit to search for + * @return #GNUNET_YES if we know this operation, + * #GNUNET_NO if this exact deposit is unknown to us + * #GNUNET_SYSERR on DB error + */ +static int +postgres_have_deposit (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_Deposit *deposit) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub), + GNUNET_PQ_query_param_uint64 (&deposit->transaction_id), + GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_deposit", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + + /* Now we check that the other information in @a deposit + also matches, and if not report inconsistencies. */ + { + struct TALER_EXCHANGEDB_Deposit deposit2; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("amount_with_fee", + &deposit2.amount_with_fee), + GNUNET_PQ_result_spec_absolute_time ("timestamp", + &deposit2.timestamp), + GNUNET_PQ_result_spec_absolute_time ("refund_deadline", + &deposit2.refund_deadline), + GNUNET_PQ_result_spec_absolute_time ("wire_deadline", + &deposit2.wire_deadline), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &deposit2.h_contract), + GNUNET_PQ_result_spec_auto_from_type ("h_wire", + &deposit2.h_wire), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee, + &deposit2.amount_with_fee)) || + (deposit->timestamp.abs_value_us != + deposit2.timestamp.abs_value_us) || + (deposit->refund_deadline.abs_value_us != + deposit2.refund_deadline.abs_value_us) || + (0 != memcmp (&deposit->h_contract, + &deposit2.h_contract, + sizeof (struct GNUNET_HashCode))) || + (0 != memcmp (&deposit->h_wire, + &deposit2.h_wire, + sizeof (struct GNUNET_HashCode))) ) + { + /* Inconsistencies detected! Does not match! (We might want to + expand the API with a 'get_deposit' function to return the + original transaction details to be used for an error message + in the future!) #3838 */ + PQclear (result); + return GNUNET_NO; + } + } + PQclear (result); + return GNUNET_YES; +} + + +/** + * Mark a deposit as tiny, thereby declaring that it cannot be + * executed by itself and should no longer be returned by + * @e iterate_ready_deposits() + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_rowid identifies the deposit row to modify + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +postgres_mark_deposit_tiny (void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid) +{ + uint64_t serial_id = rowid; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "mark_deposit_tiny", + params); + if (PGRES_COMMAND_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Mark a deposit as done, thereby declaring that it cannot be + * executed at all anymore, and should no longer be returned by + * @e iterate_ready_deposits() or @e iterate_matching_deposits(). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_rowid identifies the deposit row to modify + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +postgres_mark_deposit_done (void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid) +{ + uint64_t serial_id = rowid; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "mark_deposit_done", + params); + if (PGRES_COMMAND_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Obtain information about deposits that are ready to be executed. + * Such deposits must not be marked as "tiny" or "done", and the + * execution time must be in the past. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_cb function to call for ONE such deposit + * @param deposit_cb_cls closure for @a deposit_cb + * @return number of rows processed, 0 if none exist, + * #GNUNET_SYSERR on error + */ +static int +postgres_get_ready_deposit (void *cls, + struct TALER_EXCHANGEDB_Session *session, + TALER_EXCHANGEDB_DepositIterator deposit_cb, + void *deposit_cb_cls) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_end + }; + PGresult *result; + unsigned int n; + int ret; + + result = GNUNET_PQ_exec_prepared (session->conn, + "deposits_get_ready", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == (n = PQntuples (result))) + { + PQclear (result); + return 0; + } + GNUNET_break (1 == n); + { + struct TALER_Amount amount_with_fee; + struct TALER_Amount deposit_fee; + struct GNUNET_TIME_Absolute wire_deadline; + struct GNUNET_HashCode h_contract; + struct TALER_MerchantPublicKeyP merchant_pub; + struct TALER_CoinSpendPublicKeyP coin_pub; + uint64_t transaction_id; + uint64_t serial_id; + json_t *wire; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("serial_id", + &serial_id), + GNUNET_PQ_result_spec_uint64 ("transaction_id", + &transaction_id), + TALER_PQ_result_spec_amount ("amount_with_fee", + &amount_with_fee), + TALER_PQ_result_spec_amount ("deposit_fee", + &deposit_fee), + GNUNET_PQ_result_spec_absolute_time ("wire_deadline", + &wire_deadline), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &h_contract), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &merchant_pub), + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", + &coin_pub), + TALER_PQ_result_spec_json ("wire", + &wire), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + ret = deposit_cb (deposit_cb_cls, + serial_id, + &merchant_pub, + &coin_pub, + &amount_with_fee, + &deposit_fee, + transaction_id, + &h_contract, + wire_deadline, + wire); + GNUNET_PQ_cleanup_result (rs); + PQclear (result); + } + return (GNUNET_OK == ret) ? 1 : 0; +} + + +/** + * Obtain information about other pending deposits for the same + * destination. Those deposits must not already be "done". + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param h_wire destination of the wire transfer + * @param merchant_pub public key of the merchant + * @param deposit_cb function to call for each deposit + * @param deposit_cb_cls closure for @a deposit_cb + * @param limit maximum number of matching deposits to return + * @return number of rows processed, 0 if none exist, + * #GNUNET_SYSERR on error + */ +static int +postgres_iterate_matching_deposits (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_wire, + const struct TALER_MerchantPublicKeyP *merchant_pub, + TALER_EXCHANGEDB_DepositIterator deposit_cb, + void *deposit_cb_cls, + uint32_t limit) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_auto_from_type (h_wire), + GNUNET_PQ_query_param_uint32 (&limit), + GNUNET_PQ_query_param_end + }; + PGresult *result; + unsigned int i; + unsigned int n; + + result = GNUNET_PQ_exec_prepared (session->conn, + "deposits_iterate_matching", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == (n = PQntuples (result))) + { + PQclear (result); + return 0; + } + if (n > limit) + n = limit; + for (i=0;i<n;i++) + { + struct TALER_Amount amount_with_fee; + struct TALER_Amount deposit_fee; + struct GNUNET_TIME_Absolute wire_deadline; + struct GNUNET_HashCode h_contract; + struct TALER_MerchantPublicKeyP merchant_pub; + struct TALER_CoinSpendPublicKeyP coin_pub; + uint64_t transaction_id; + uint64_t serial_id; + int ret; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("serial_id", + &serial_id), + GNUNET_PQ_result_spec_uint64 ("transaction_id", + &transaction_id), + TALER_PQ_result_spec_amount ("amount_with_fee", + &amount_with_fee), + TALER_PQ_result_spec_amount ("deposit_fee", + &deposit_fee), + GNUNET_PQ_result_spec_absolute_time ("wire_deadline", + &wire_deadline), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &h_contract), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &merchant_pub), + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", + &coin_pub), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, i)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + ret = deposit_cb (deposit_cb_cls, + serial_id, + &merchant_pub, + &coin_pub, + &amount_with_fee, + &deposit_fee, + transaction_id, + &h_contract, + wire_deadline, + NULL); + GNUNET_PQ_cleanup_result (rs); + PQclear (result); + if (GNUNET_OK != ret) + break; + } + return i; +} + + +/** + * Insert information about deposited coin into the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session connection to the database + * @param deposit deposit information to store + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +postgres_insert_deposit (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_Deposit *deposit) +{ + PGresult *result; + int ret; + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub), + GNUNET_PQ_query_param_rsa_public_key (deposit->coin.denom_pub.rsa_public_key), + GNUNET_PQ_query_param_rsa_signature (deposit->coin.denom_sig.rsa_signature), + GNUNET_PQ_query_param_uint64 (&deposit->transaction_id), + TALER_PQ_query_param_amount (&deposit->amount_with_fee), + TALER_PQ_query_param_amount (&deposit->deposit_fee), + GNUNET_PQ_query_param_absolute_time (&deposit->timestamp), + GNUNET_PQ_query_param_absolute_time (&deposit->refund_deadline), + GNUNET_PQ_query_param_absolute_time (&deposit->wire_deadline), + GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub), + GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract), + GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire), + GNUNET_PQ_query_param_auto_from_type (&deposit->csig), + TALER_PQ_query_param_json (deposit->wire), + GNUNET_PQ_query_param_end + }; + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_deposit", + params); + } + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + ret = GNUNET_SYSERR; + } + else + { + ret = GNUNET_OK; + } + PQclear (result); + return ret; +} + + +/** + * Lookup refresh session data under the given @a session_hash. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database handle to use + * @param session_hash hash over the melt to use to locate the session + * @param[out] refresh_session where to store the result, can be NULL + * to just check if the session exists + * @return #GNUNET_YES on success, + * #GNUNET_NO if not found, + * #GNUNET_SYSERR on DB failure + */ +static int +postgres_get_refresh_session (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + struct TALER_EXCHANGEDB_RefreshSession *refresh_session) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_session", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == PQntuples (result)); + if (NULL == refresh_session) + { + /* We're done if the caller is only interested in whether the + * session exists or not */ + PQclear (result); + return GNUNET_YES; + } + memset (refresh_session, + 0, + sizeof (struct TALER_EXCHANGEDB_RefreshSession)); + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint16 ("num_oldcoins", + &refresh_session->num_oldcoins), + GNUNET_PQ_result_spec_uint16 ("num_newcoins", + &refresh_session->num_newcoins), + GNUNET_PQ_result_spec_uint16 ("noreveal_index", + &refresh_session->noreveal_index), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + } + PQclear (result); + return GNUNET_YES; +} + + +/** + * Store new refresh session data under the given @a session_hash. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database handle to use + * @param session_hash hash over the melt to use to locate the session + * @param refresh_session session data to store + * @return #GNUNET_YES on success, + * #GNUNET_SYSERR on DB failure + */ +static int +postgres_create_refresh_session (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + const struct TALER_EXCHANGEDB_RefreshSession *refresh_session) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&refresh_session->num_oldcoins), + GNUNET_PQ_query_param_uint16 (&refresh_session->num_newcoins), + GNUNET_PQ_query_param_uint16 (&refresh_session->noreveal_index), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_session", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Insert a coin we know of into the DB. The coin can then be referenced by + * tables for deposits, lock and refresh functionality. + * + * @param cls plugin closure + * @param session the shared database session + * @param coin_info the public coin info + * @return #GNUNET_SYSERR upon error; #GNUNET_OK upon success + */ +static int +insert_known_coin (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinPublicInfo *coin_info) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub), + GNUNET_PQ_query_param_rsa_public_key (coin_info->denom_pub.rsa_public_key), + GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature), + GNUNET_PQ_query_param_end + }; + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_known_coin", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Retrieve the record for a known coin. + * + * @param cls the plugin closure + * @param session the database session handle + * @param coin_pub the public key of the coin to search for + * @param coin_info place holder for the returned coin information object + * @return #GNUNET_SYSERR upon error; #GNUNET_NO if no coin is found; #GNUNET_OK + * if upon succesfullying retrieving the record data info @a + * coin_info + */ +static int +get_known_coin (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct TALER_CoinPublicInfo *coin_info) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_end + }; + int nrows; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_known_coin", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + nrows = PQntuples (result); + if (0 == nrows) + { + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); /* due to primary key */ + if (NULL == coin_info) + return GNUNET_YES; + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &coin_info->denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &coin_info->denom_sig.rsa_signature), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + PQclear (result); + GNUNET_break (0); + return GNUNET_SYSERR; + } + } + PQclear (result); + coin_info->coin_pub = *coin_pub; + return GNUNET_OK; +} + + +/** + * Store the given /refresh/melt request in the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param oldcoin_index index of the coin to store + * @param melt melt operation details to store; includes + * the session hash of the melt + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ +static int +postgres_insert_refresh_melt (void *cls, + struct TALER_EXCHANGEDB_Session *session, + uint16_t oldcoin_index, + const struct TALER_EXCHANGEDB_RefreshMelt *melt) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&melt->coin.coin_pub), + GNUNET_PQ_query_param_auto_from_type (&melt->session_hash), + GNUNET_PQ_query_param_uint16 (&oldcoin_index), + GNUNET_PQ_query_param_auto_from_type (&melt->coin_sig), + TALER_PQ_query_param_amount (&melt->amount_with_fee), + TALER_PQ_query_param_amount (&melt->melt_fee), + GNUNET_PQ_query_param_end + }; + int ret; + + /* check if the coin is already known */ + ret = get_known_coin (cls, + session, + &melt->coin.coin_pub, + NULL); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_NO == ret) /* if not, insert it */ + { + ret = insert_known_coin (cls, + session, + &melt->coin); + if (ret == GNUNET_SYSERR) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + } + /* insert the melt */ + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_melt", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Get information about melted coin details from the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param session_hash session hash of the melt operation + * @param oldcoin_index index of the coin to retrieve + * @param melt melt data to fill in, can be NULL + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ +static int +postgres_get_refresh_melt (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t oldcoin_index, + struct TALER_EXCHANGEDB_RefreshMelt *melt) +{ + PGresult *result; + struct TALER_CoinPublicInfo coin; + struct TALER_CoinSpendSignatureP coin_sig; + struct TALER_Amount amount_with_fee; + struct TALER_Amount melt_fee; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&oldcoin_index), + GNUNET_PQ_query_param_end + }; + int nrows; + + /* check if the melt record exists and get it */ + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_melt", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "get_refresh_melt() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + GNUNET_assert (1 == nrows); /* due to primary key constraint */ + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin.coin_pub), + GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &coin_sig), + TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee), + TALER_PQ_result_spec_amount ("melt_fee", &melt_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + } + /* fetch the coin info and denomination info */ + if (GNUNET_OK != get_known_coin (cls, + session, + &coin.coin_pub, + &coin)) + return GNUNET_SYSERR; + if (NULL == melt) + { + GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (coin.denom_pub.rsa_public_key); + return GNUNET_OK; + } + melt->coin = coin; + melt->coin_sig = coin_sig; + melt->session_hash = *session_hash; + melt->amount_with_fee = amount_with_fee; + melt->melt_fee = melt_fee; + return GNUNET_OK; +} + + +/** + * Store in the database which coin(s) we want to create + * in a given refresh operation. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param num_newcoins number of coins to generate, size of the @a denom_pubs array + * @param denom_pubs array denominations of the coins to create + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ +static int +postgres_insert_refresh_order (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t num_newcoins, + const struct TALER_DenominationPublicKey *denom_pubs) +{ + unsigned int i; + + for (i=0;i<(unsigned int) num_newcoins;i++) + { + uint16_t newcoin_off = (uint16_t) i; + PGresult *result; + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint16 (&newcoin_off), + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_rsa_public_key (denom_pubs[i].rsa_public_key), + GNUNET_PQ_query_param_end + }; + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_order", + params); + } + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 != strcmp ("1", PQcmdTuples (result))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + PQclear (result); + } + return GNUNET_OK; +} + + +/** + * We allocated some @a denom_pubs information, but now need + * to abort. Free allocated memory. + * + * @param denom_pubs data to free (but not the array itself) + * @param denom_pubs_len length of @a denom_pubs array + */ +static void +free_dpk_result (struct TALER_DenominationPublicKey *denom_pubs, + unsigned int denom_pubs_len) +{ + unsigned int i; + + for (i=0;i<denom_pubs_len;i++) + { + GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key); + denom_pubs[i].rsa_public_key = NULL; + } +} + + +/** + * Lookup in the database the coins that we want to + * create in the given refresh operation. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param num_newcoins size of the array of the @a denom_pubs array + * @param denom_pubs where to store the deomination keys + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ +static int +postgres_get_refresh_order (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t num_newcoins, + struct TALER_DenominationPublicKey *denom_pubs) +{ + unsigned int i; + + for (i=0;i<(unsigned int) num_newcoins;i++) + { + uint16_t newcoin_off = (uint16_t) i; + PGresult *result; + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&newcoin_off), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_order", + params); + } + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + free_dpk_result (denom_pubs, i); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + /* FIXME: may want to distinguish between different error cases! */ + free_dpk_result (denom_pubs, i); + return GNUNET_SYSERR; + } + GNUNET_assert (1 == PQntuples (result)); + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &denom_pubs[i].rsa_public_key), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + PQclear (result); + GNUNET_break (0); + free_dpk_result (denom_pubs, i); + return GNUNET_SYSERR; + } + PQclear (result); + } + } + return GNUNET_OK; +} + + +/** + * Store information about the commitment of the + * given coin for the given refresh session in the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension) + * @param num_newcoins coin index size of the @a commit_coins array + * @param commit_coins array of coin commitments to store + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on error + */ +static int +postgres_insert_refresh_commit_coins (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_newcoins, + const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins) +{ + char *rle; + size_t rle_size; + PGresult *result; + unsigned int i; + uint16_t coin_off; + + for (i=0;i<(unsigned int) num_newcoins;i++) + { + rle = TALER_refresh_link_encrypted_encode (commit_coins[i].refresh_link, + &rle_size); + if (NULL == rle) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + coin_off = (uint16_t) i; + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&cnc_index), + GNUNET_PQ_query_param_uint16 (&coin_off), + GNUNET_PQ_query_param_fixed_size (rle, + rle_size), + GNUNET_PQ_query_param_fixed_size (commit_coins[i].coin_ev, + commit_coins[i].coin_ev_size), + GNUNET_PQ_query_param_end + }; + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_commit_coin", + params); + } + GNUNET_free (rle); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 != strcmp ("1", PQcmdTuples (result))) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + } + return GNUNET_OK; +} + + +/** + * We allocated some @a commit_coin information, but now need + * to abort. Free allocated memory. + * + * @param commit_coins data to free (but not the array itself) + * @param commit_coins_len length of @a commit_coins array + */ +static void +free_cc_result (struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins, + unsigned int commit_coins_len) +{ + unsigned int i; + + for (i=0;i<commit_coins_len;i++) + { + GNUNET_free (commit_coins[i].refresh_link); + commit_coins[i].refresh_link = NULL; + GNUNET_free (commit_coins[i].coin_ev); + commit_coins[i].coin_ev = NULL; + commit_coins[i].coin_ev_size = 0; + } +} + + +/** + * Obtain information about the commitment of the + * given coin of the given refresh session from the database. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index set index (1st dimension) + * @param num_newcoins size of the @a commit_coins array + * @param[out] commit_coins array of coin commitments to return + * @return #GNUNET_OK on success + * #GNUNET_NO if not found + * #GNUNET_SYSERR on error + */ +static int +postgres_get_refresh_commit_coins (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_newcoins, + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins) +{ + unsigned int i; + + for (i=0;i<(unsigned int) num_newcoins;i++) + { + uint16_t newcoin_off = (uint16_t) i; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&cnc_index), + GNUNET_PQ_query_param_uint16 (&newcoin_off), + GNUNET_PQ_query_param_end + }; + void *c_buf; + size_t c_buf_size; + void *rl_buf; + size_t rl_buf_size; + struct TALER_RefreshLinkEncrypted *rl; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_commit_coin", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + free_cc_result (commit_coins, i); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + free_cc_result (commit_coins, i); + return GNUNET_NO; + } + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_variable_size ("link_vector_enc", + &rl_buf, + &rl_buf_size), + GNUNET_PQ_result_spec_variable_size ("coin_ev", + &c_buf, + &c_buf_size), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_YES != + GNUNET_PQ_extract_result (result, rs, 0)) + { + PQclear (result); + free_cc_result (commit_coins, i); + return GNUNET_SYSERR; + } + } + PQclear (result); + if (rl_buf_size < sizeof (struct TALER_CoinSpendPrivateKeyP)) + { + GNUNET_free (c_buf); + GNUNET_free (rl_buf); + free_cc_result (commit_coins, i); + return GNUNET_SYSERR; + } + rl = TALER_refresh_link_encrypted_decode (rl_buf, + rl_buf_size); + GNUNET_free (rl_buf); + commit_coins[i].refresh_link = rl; + commit_coins[i].coin_ev = c_buf; + commit_coins[i].coin_ev_size = c_buf_size; + } + return GNUNET_YES; +} + + +/** + * Store the commitment to the given (encrypted) refresh link data + * for the given refresh session. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension) + * @param num_links size of the @a links array to return + * @param[out] links array of link information to store return + * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success + */ +static int +postgres_insert_refresh_commit_links (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_links, + const struct TALER_RefreshCommitLinkP *links) +{ + uint16_t i; + + for (i=0;i<num_links;i++) + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_auto_from_type (&links[i].transfer_pub), + GNUNET_PQ_query_param_uint16 (&cnc_index), + GNUNET_PQ_query_param_uint16 (&i), + GNUNET_PQ_query_param_auto_from_type (&links[i].shared_secret_enc), + GNUNET_PQ_query_param_end + }; + + PGresult *result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_commit_link", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + + if (0 != strcmp ("1", PQcmdTuples (result))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + PQclear (result); + } + return GNUNET_OK; +} + + +/** + * Obtain the commited (encrypted) refresh link data + * for the given refresh session. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension) + * @param num_links size of the @a commit_link array + * @param[out] links array of link information to return + * @return #GNUNET_SYSERR on internal error, + * #GNUNET_NO if commitment was not found + * #GNUNET_OK on success + */ +static int +postgres_get_refresh_commit_links (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_links, + struct TALER_RefreshCommitLinkP *links) +{ + uint16_t i; + + for (i=0;i<num_links;i++) + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&cnc_index), + GNUNET_PQ_query_param_uint16 (&i), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_commit_link", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", + &links[i].transfer_pub), + GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", + &links[i].shared_secret_enc), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_YES != + GNUNET_PQ_extract_result (result, rs, 0)) + { + PQclear (result); + return GNUNET_SYSERR; + } + } + PQclear (result); + } + return GNUNET_OK; +} + + +/** + * Get all of the information from the given melt commit operation. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @return NULL if the @a session_hash does not correspond to any known melt + * operation + */ +static struct TALER_EXCHANGEDB_MeltCommitment * +postgres_get_melt_commitment (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash) +{ + struct TALER_EXCHANGEDB_RefreshSession rs; + struct TALER_EXCHANGEDB_MeltCommitment *mc; + uint16_t cnc_index; + unsigned int i; + + if (GNUNET_OK != + postgres_get_refresh_session (cls, + session, + session_hash, + &rs)) + return NULL; + mc = GNUNET_new (struct TALER_EXCHANGEDB_MeltCommitment); + mc->num_newcoins = rs.num_newcoins; + mc->num_oldcoins = rs.num_oldcoins; + mc->melts = GNUNET_malloc (mc->num_oldcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshMelt)); + for (i=0;i<mc->num_oldcoins;i++) + if (GNUNET_OK != + postgres_get_refresh_melt (cls, + session, + session_hash, + (uint16_t) i, + &mc->melts[i])) + goto cleanup; + mc->denom_pubs = GNUNET_malloc (mc->num_newcoins * + sizeof (struct TALER_DenominationPublicKey)); + if (GNUNET_OK != + postgres_get_refresh_order (cls, + session, + session_hash, + mc->num_newcoins, + mc->denom_pubs)) + goto cleanup; + for (cnc_index=0;cnc_index<TALER_CNC_KAPPA;cnc_index++) + { + mc->commit_coins[cnc_index] + = GNUNET_malloc (mc->num_newcoins * + sizeof (struct TALER_EXCHANGEDB_RefreshCommitCoin)); + if (GNUNET_OK != + postgres_get_refresh_commit_coins (cls, + session, + session_hash, + cnc_index, + mc->num_newcoins, + mc->commit_coins[cnc_index])) + goto cleanup; + mc->commit_links[cnc_index] + = GNUNET_malloc (mc->num_oldcoins * + sizeof (struct TALER_RefreshCommitLinkP)); + if (GNUNET_OK != + postgres_get_refresh_commit_links (cls, + session, + session_hash, + cnc_index, + mc->num_oldcoins, + mc->commit_links[cnc_index])) + goto cleanup; + } + return mc; + + cleanup: + common_free_melt_commitment (cls, mc); + return NULL; +} + + +/** + * Insert signature of a new coin generated during refresh into + * the database indexed by the refresh session and the index + * of the coin. This data is later used should an old coin + * be used to try to obtain the private keys during "/refresh/link". + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param newcoin_index coin index + * @param ev_sig coin signature + * @return #GNUNET_OK on success + */ +static int +postgres_insert_refresh_out (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t newcoin_index, + const struct TALER_DenominationSignature *ev_sig) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_uint16 (&newcoin_index), + GNUNET_PQ_query_param_rsa_signature (ev_sig->rsa_signature), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_refresh_out", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Obtain the link data of a coin, that is the encrypted link + * information, the denomination keys and the signatures. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param session_hash refresh session to get linkage data for + * @return all known link data for the session + */ +static struct TALER_EXCHANGEDB_LinkDataList * +postgres_get_link_data_list (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash) +{ + struct TALER_EXCHANGEDB_LinkDataList *ldl; + struct TALER_EXCHANGEDB_LinkDataList *pos; + int i; + int nrows; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (session_hash), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_link", + params); + + ldl = NULL; + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return NULL; + } + nrows = PQntuples (result); + if (0 == nrows) + { + PQclear (result); + return NULL; + } + + for (i = 0; i < nrows; i++) + { + struct TALER_RefreshLinkEncrypted *link_enc; + struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; + struct GNUNET_CRYPTO_rsa_Signature *sig; + void *ld_buf; + size_t ld_buf_size; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_variable_size ("link_vector_enc", + &ld_buf, + &ld_buf_size), + GNUNET_PQ_result_spec_rsa_signature ("ev_sig", + &sig), + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &denom_pub), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, i)) + { + PQclear (result); + GNUNET_break (0); + common_free_link_data_list (cls, + ldl); + return NULL; + } + if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) + { + PQclear (result); + GNUNET_free (ld_buf); + common_free_link_data_list (cls, + ldl); + return NULL; + } + link_enc = TALER_refresh_link_encrypted_decode (ld_buf, + ld_buf_size); + GNUNET_free (ld_buf); + pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkDataList); + pos->next = ldl; + pos->link_data_enc = link_enc; + pos->denom_pub.rsa_public_key = denom_pub; + pos->ev_sig.rsa_signature = sig; + ldl = pos; + } + return ldl; +} + + +/** + * Obtain shared secret and transfer public key from the public key of + * the coin. This information and the link information returned by + * #postgres_get_link_data_list() enable the owner of an old coin to + * determine the private keys of the new coins after the melt. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param coin_pub public key of the coin + * @param tdc function to call for each session the coin was melted into + * @param tdc_cls closure for @a tdc + * @return #GNUNET_OK on success, + * #GNUNET_NO on failure (not found) + * #GNUNET_SYSERR on internal failure (database issue) + */ +static int +postgres_get_transfer (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + TALER_EXCHANGEDB_TransferDataCallback tdc, + void *tdc_cls) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_end + }; + PGresult *result; + int nrows; + int i; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_transfer", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + nrows = PQntuples (result); + if (0 == nrows) + { + /* no matches found */ + PQclear (result); + return GNUNET_NO; + } + for (i=0;i<nrows;i++) + { + struct GNUNET_HashCode session_hash; + struct TALER_TransferPublicKeyP transfer_pub; + struct TALER_EncryptedLinkSecretP shared_secret_enc; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", &transfer_pub), + GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", &shared_secret_enc), + GNUNET_PQ_result_spec_auto_from_type ("session_hash", &session_hash), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + PQclear (result); + GNUNET_break (0); + return GNUNET_SYSERR; + } + tdc (tdc_cls, + &session_hash, + &transfer_pub, + &shared_secret_enc); + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Compile a list of all (historic) transactions performed + * with the given coin (/refresh/melt and /deposit operations). + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param coin_pub coin to investigate + * @return list of transactions, NULL if coin is fresh + */ +static struct TALER_EXCHANGEDB_TransactionList * +postgres_get_coin_transactions (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub) +{ + struct TALER_EXCHANGEDB_TransactionList *head; + + head = NULL; + /* check deposits */ + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub), + GNUNET_PQ_query_param_end + }; + int nrows; + int i; + PGresult *result; + struct TALER_EXCHANGEDB_TransactionList *tl; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_deposit_with_coin_pub", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + PQclear (result); + goto cleanup; + } + nrows = PQntuples (result); + for (i = 0; i < nrows; i++) + { + struct TALER_EXCHANGEDB_Deposit *deposit; + + deposit = GNUNET_new (struct TALER_EXCHANGEDB_Deposit); + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", + &deposit->coin.denom_pub.rsa_public_key), + GNUNET_PQ_result_spec_rsa_signature ("denom_sig", + &deposit->coin.denom_sig.rsa_signature), + GNUNET_PQ_result_spec_uint64 ("transaction_id", + &deposit->transaction_id), + TALER_PQ_result_spec_amount ("amount_with_fee", + &deposit->amount_with_fee), + TALER_PQ_result_spec_amount ("deposit_fee", + &deposit->deposit_fee), + GNUNET_PQ_result_spec_absolute_time ("timestamp", + &deposit->timestamp), + GNUNET_PQ_result_spec_absolute_time ("refund_deadline", + &deposit->refund_deadline), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &deposit->merchant_pub), + GNUNET_PQ_result_spec_auto_from_type ("h_contract", + &deposit->h_contract), + GNUNET_PQ_result_spec_auto_from_type ("h_wire", + &deposit->h_wire), + TALER_PQ_result_spec_json ("wire", + &deposit->wire), + GNUNET_PQ_result_spec_auto_from_type ("coin_sig", + &deposit->csig), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, i)) + { + GNUNET_break (0); + GNUNET_free (deposit); + PQclear (result); + goto cleanup; + } + deposit->coin.coin_pub = *coin_pub; + } + tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); + tl->next = head; + tl->type = TALER_EXCHANGEDB_TT_DEPOSIT; + tl->details.deposit = deposit; + head = tl; + continue; + } + PQclear (result); + } + /* Handle refreshing */ + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub), + GNUNET_PQ_query_param_end + }; + int nrows; + int i; + PGresult *result; + struct TALER_EXCHANGEDB_TransactionList *tl; + + /* check if the melt record exists and get it */ + result = GNUNET_PQ_exec_prepared (session->conn, + "get_refresh_melt_by_coin", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + goto cleanup; + } + nrows = PQntuples (result); + for (i=0;i<nrows;i++) + { + struct TALER_EXCHANGEDB_RefreshMelt *melt; + + melt = GNUNET_new (struct TALER_EXCHANGEDB_RefreshMelt); + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("session_hash", + &melt->session_hash), + /* oldcoin_index not needed */ + GNUNET_PQ_result_spec_auto_from_type ("coin_sig", + &melt->coin_sig), + TALER_PQ_result_spec_amount ("amount_with_fee", + &melt->amount_with_fee), + TALER_PQ_result_spec_amount ("melt_fee", + &melt->melt_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + GNUNET_free (melt); + PQclear (result); + goto cleanup; + } + melt->coin.coin_pub = *coin_pub; + } + tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList); + tl->next = head; + tl->type = TALER_EXCHANGEDB_TT_REFRESH_MELT; + tl->details.melt = melt; + head = tl; + continue; + } + PQclear (result); + } + return head; + cleanup: + if (NULL != head) + common_free_coin_transaction_list (cls, + head); + return NULL; +} + + +/** + * Lookup the list of Taler transactions that were aggregated + * into a wire transfer by the respective @a wtid. + * + * @param cls closure + * @param session database connection + * @param wtid the raw wire transfer identifier we used + * @param cb function to call on each transaction found + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors, + * #GNUNET_NO if we found no results + */ +static int +postgres_lookup_wire_transfer (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_WireTransferIdentifierRawP *wtid, + TALER_EXCHANGEDB_WireTransferDataCallback cb, + void *cb_cls) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (wtid), + GNUNET_PQ_query_param_end + }; + int nrows; + int i; + + /* check if the melt record exists and get it */ + result = GNUNET_PQ_exec_prepared (session->conn, + "lookup_transactions", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "lookup_wire_transfer() returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + for (i=0;i<nrows;i++) + { + struct GNUNET_HashCode h_contract; + struct GNUNET_HashCode h_wire; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_MerchantPublicKeyP merchant_pub; + uint64_t transaction_id; + struct GNUNET_TIME_Absolute exec_time; + struct TALER_Amount coin_amount; + struct TALER_Amount coin_fee; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("h_contract", &h_contract), + GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire), + GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub), + GNUNET_PQ_result_spec_uint64 ("transaction_id", &transaction_id), + GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time), + TALER_PQ_result_spec_amount ("coin_amount", &coin_amount), + TALER_PQ_result_spec_amount ("coin_fee", &coin_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, i)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + &merchant_pub, + &h_wire, + &h_contract, + transaction_id, + &coin_pub, + &coin_amount, + &coin_fee); + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Try to find the wire transfer details for a deposit operation. + * If we did not execute the deposit yet, return when it is supposed + * to be executed. + * + * @param cls closure + * @param session database connection + * @param h_contract hash of the contract + * @param h_wire hash of merchant wire details + * @param coin_pub public key of deposited coin + * @param merchant_pub merchant public key + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure to pass to @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors, + * #GNUNET_NO if nothing was found + */ +static int +postgres_wire_lookup_deposit_wtid (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id, + TALER_EXCHANGEDB_DepositWtidCallback cb, + void *cb_cls) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_auto_from_type (h_contract), + GNUNET_PQ_query_param_auto_from_type (h_wire), + GNUNET_PQ_query_param_uint64 (&transaction_id), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_end + }; + int nrows; + + /* check if the melt record exists and get it */ + result = GNUNET_PQ_exec_prepared (session->conn, + "lookup_deposit_wtid", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "lookup_deposit_wtid returned 0 matching rows\n"); + PQclear (result); + + /* Check if transaction exists in deposits, so that we just + do not have a WTID yet, if so, do call the CB with a NULL wtid + and return GNUNET_YES! */ + { + struct GNUNET_PQ_QueryParam params2[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_uint64 (&transaction_id), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_auto_from_type (h_contract), + GNUNET_PQ_query_param_auto_from_type (h_wire), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "get_deposit_for_wtid", + params2); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + } + nrows = PQntuples (result); + if (0 == nrows) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "get_deposit_for_wtid returned 0 matching rows\n"); + PQclear (result); + return GNUNET_NO; + } + + /* Ok, we're aware of the transaction, but it has not yet been + executed */ + { + struct GNUNET_TIME_Absolute exec_time; + struct TALER_Amount coin_amount; + struct TALER_Amount coin_fee; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_amount ("amount_with_fee", &coin_amount), + TALER_PQ_result_spec_amount ("deposit_fee", &coin_fee), + GNUNET_PQ_result_spec_absolute_time ("wire_deadline", &exec_time), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + NULL, + &coin_amount, + &coin_fee, + exec_time); + PQclear (result); + return GNUNET_YES; + } + } + if (1 != nrows) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + { + struct TALER_WireTransferIdentifierRawP wtid; + struct GNUNET_TIME_Absolute exec_time; + struct TALER_Amount coin_amount; + struct TALER_Amount coin_fee; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("wtid_raw", &wtid), + GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time), + TALER_PQ_result_spec_amount ("coin_amount", &coin_amount), + TALER_PQ_result_spec_amount ("coin_fee", &coin_fee), + GNUNET_PQ_result_spec_end + }; + if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + &wtid, + &coin_amount, + &coin_fee, + exec_time); + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Function called to insert aggregation information into the DB. + * + * @param cls closure + * @param session database connection + * @param wtid the raw wire transfer identifier we used + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param coin_pub which public key was this payment about + * @param coin_value amount contributed by this coin in total + * @param coin_fee deposit fee charged by exchange for this coin + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ +static int +postgres_insert_aggregation_tracking (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_value, + const struct TALER_Amount *coin_fee) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (h_contract), + GNUNET_PQ_query_param_auto_from_type (h_wire), + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), + GNUNET_PQ_query_param_uint64 (&transaction_id), + GNUNET_PQ_query_param_auto_from_type (wtid), + GNUNET_PQ_query_param_absolute_time (&execution_time), + TALER_PQ_query_param_amount (coin_value), + TALER_PQ_query_param_amount (coin_fee), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "insert_aggregation_tracking", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 != strcmp ("1", PQcmdTuples (result))) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Function called to insert wire transfer commit data into the DB. + * + * @param cls closure + * @param session database connection + * @param type type of the wire transfer (i.e. "sepa") + * @param buf buffer with wire transfer preparation data + * @param buf_size number of bytes in @a buf + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ +static int +postgres_wire_prepare_data_insert (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const char *type, + const char *buf, + size_t buf_size) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1), + GNUNET_PQ_query_param_fixed_size (buf, buf_size), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "wire_prepare_data_insert", + params); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Function called to mark wire transfer commit data as finished. + * + * @param cls closure + * @param session database connection + * @param rowid which entry to mark as finished + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ +static int +postgres_wire_prepare_data_mark_finished (void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid) +{ + uint64_t serial_id = rowid; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_uint64 (&serial_id), + GNUNET_PQ_query_param_end + }; + PGresult *result; + + result = GNUNET_PQ_exec_prepared (session->conn, + "wire_prepare_data_mark_done", + params); + if (PGRES_COMMAND_OK != + PQresultStatus (result)) + { + BREAK_DB_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Function called to get an unfinished wire transfer + * preparation data. Fetches at most one item. + * + * @param cls closure + * @param session database connection + * @param type type fo the wire transfer (i.e. "sepa") + * @param cb function to call for ONE unfinished item + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, + * #GNUNET_NO if there are no entries, + * #GNUNET_SYSERR on DB errors + */ +static int +postgres_wire_prepare_data_get (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const char *type, + TALER_EXCHANGEDB_WirePreparationCallback cb, + void *cb_cls) +{ + PGresult *result; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1), + GNUNET_PQ_query_param_end + }; + + result = GNUNET_PQ_exec_prepared (session->conn, + "wire_prepare_data_get", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + QUERY_ERR (result); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + if (1 != PQntuples (result)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + + { + uint64_t serial_id; + void *buf = NULL; + size_t buf_size; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("serial_id", + &serial_id), + GNUNET_PQ_result_spec_variable_size ("buf", + &buf, + &buf_size), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + 0)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } + cb (cb_cls, + serial_id, + buf, + buf_size); + GNUNET_PQ_cleanup_result (rs); + } + PQclear (result); + return GNUNET_OK; +} + + +/** + * Initialize Postgres database subsystem. + * + * @param cls a configuration instance + * @return NULL on error, otherwise a `struct TALER_EXCHANGEDB_Plugin` + */ +void * +libtaler_plugin_exchangedb_postgres_init (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct PostgresClosure *pg; + struct TALER_EXCHANGEDB_Plugin *plugin; + + pg = GNUNET_new (struct PostgresClosure); + + if (0 != pthread_key_create (&pg->db_conn_threadlocal, + &db_conn_destroy)) + { + TALER_LOG_ERROR ("Cannnot create pthread key.\n"); + GNUNET_free (pg); + return NULL; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchangedb-postgres", + "db_conn_str", + &pg->connection_cfg_str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchangedb-postgres", + "db_conn_str"); + GNUNET_free (pg); + return NULL; + } + plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin); + plugin->cls = pg; + plugin->get_session = &postgres_get_session; + plugin->drop_temporary = &postgres_drop_temporary; + plugin->create_tables = &postgres_create_tables; + plugin->start = &postgres_start; + plugin->commit = &postgres_commit; + plugin->rollback = &postgres_rollback; + plugin->insert_denomination_info = &postgres_insert_denomination_info; + plugin->get_denomination_info = &postgres_get_denomination_info; + plugin->reserve_get = &postgres_reserve_get; + plugin->reserves_in_insert = &postgres_reserves_in_insert; + plugin->get_withdraw_info = &postgres_get_withdraw_info; + plugin->insert_withdraw_info = &postgres_insert_withdraw_info; + plugin->get_reserve_history = &postgres_get_reserve_history; + plugin->free_reserve_history = &common_free_reserve_history; + plugin->have_deposit = &postgres_have_deposit; + plugin->mark_deposit_tiny = &postgres_mark_deposit_tiny; + plugin->mark_deposit_done = &postgres_mark_deposit_done; + plugin->get_ready_deposit = &postgres_get_ready_deposit; + plugin->iterate_matching_deposits = &postgres_iterate_matching_deposits; + plugin->insert_deposit = &postgres_insert_deposit; + plugin->get_refresh_session = &postgres_get_refresh_session; + plugin->create_refresh_session = &postgres_create_refresh_session; + plugin->insert_refresh_melt = &postgres_insert_refresh_melt; + plugin->get_refresh_melt = &postgres_get_refresh_melt; + plugin->insert_refresh_order = &postgres_insert_refresh_order; + plugin->get_refresh_order = &postgres_get_refresh_order; + plugin->insert_refresh_commit_coins = &postgres_insert_refresh_commit_coins; + plugin->get_refresh_commit_coins = &postgres_get_refresh_commit_coins; + plugin->insert_refresh_commit_links = &postgres_insert_refresh_commit_links; + plugin->get_refresh_commit_links = &postgres_get_refresh_commit_links; + plugin->get_melt_commitment = &postgres_get_melt_commitment; + plugin->free_melt_commitment = &common_free_melt_commitment; + plugin->insert_refresh_out = &postgres_insert_refresh_out; + plugin->get_link_data_list = &postgres_get_link_data_list; + plugin->free_link_data_list = &common_free_link_data_list; + plugin->get_transfer = &postgres_get_transfer; + plugin->get_coin_transactions = &postgres_get_coin_transactions; + plugin->free_coin_transaction_list = &common_free_coin_transaction_list; + plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer; + plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid; + plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking; + plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert; + plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished; + plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get; + return plugin; +} + + +/** + * Shutdown Postgres database subsystem. + * + * @param cls a `struct TALER_EXCHANGEDB_Plugin` + * @return NULL (always) + */ +void * +libtaler_plugin_exchangedb_postgres_done (void *cls) +{ + struct TALER_EXCHANGEDB_Plugin *plugin = cls; + struct PostgresClosure *pg = plugin->cls; + + GNUNET_free (pg->connection_cfg_str); + GNUNET_free (pg); + GNUNET_free (plugin); + return NULL; +} + +/* end of plugin_exchangedb_postgres.c */ diff --git a/src/exchangedb/test-exchange-db-postgres.conf b/src/exchangedb/test-exchange-db-postgres.conf new file mode 100644 index 000000000..0822bab44 --- /dev/null +++ b/src/exchangedb/test-exchange-db-postgres.conf @@ -0,0 +1,8 @@ +[exchange] +#The DB plugin to use +DB = postgres + +[exchangedb-postgres] + +#The connection string the plugin has to use for connecting to the database +DB_CONN_STR = postgres:///talercheck diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c new file mode 100644 index 000000000..df1adf561 --- /dev/null +++ b/src/exchangedb/test_exchangedb.c @@ -0,0 +1,907 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchangedb/test_exchangedb.c + * @brief test cases for DB interaction functions + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_exchangedb_plugin.h" + +static int result; + +#define FAILIF(cond) \ + do { \ + if (!(cond)){ break;} \ + GNUNET_break (0); \ + goto drop; \ + } while (0) + + +#define RND_BLK(ptr) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) + +#define ZR_BLK(ptr) \ + memset (ptr, 0, sizeof (*ptr)) + + +#define CURRENCY "EUR" + +static struct TALER_EXCHANGEDB_Plugin *plugin; + +/** + * Checks if the given reserve has the given amount of balance and expiry + * + * @param session the database connection + * @param pub the public key of the reserve + * @param value balance value + * @param fraction balance fraction + * @param currency currency of the reserve + * @return #GNUNET_OK if the given reserve has the same balance and expiration + * as the given parameters; #GNUNET_SYSERR if not + */ +static int +check_reserve (struct TALER_EXCHANGEDB_Session *session, + const struct TALER_ReservePublicKeyP *pub, + uint64_t value, + uint32_t fraction, + const char *currency) +{ + struct TALER_EXCHANGEDB_Reserve reserve; + + reserve.pub = *pub; + + FAILIF (GNUNET_OK != + plugin->reserve_get (plugin->cls, + session, + &reserve)); + FAILIF (value != reserve.balance.value); + FAILIF (fraction != reserve.balance.fraction); + FAILIF (0 != strcmp (currency, reserve.balance.currency)); + + return GNUNET_OK; + drop: + return GNUNET_SYSERR; +} + + +struct DenomKeyPair +{ + struct TALER_DenominationPrivateKey priv; + struct TALER_DenominationPublicKey pub; +}; + + +/** + * Destroy a denomination key pair. The key is not necessarily removed from the DB. + * + * @param dkp the keypair to destroy + */ +static void +destroy_denom_key_pair (struct DenomKeyPair *dkp) +{ + GNUNET_CRYPTO_rsa_public_key_free (dkp->pub.rsa_public_key); + GNUNET_CRYPTO_rsa_private_key_free (dkp->priv.rsa_private_key); + GNUNET_free (dkp); +} + + +/** + * Create a denominaiton key pair by registering the denomination in the DB. + * + * @param size the size of the denomination key + * @param session the DB session + * @return the denominaiton key pair; NULL upon error + */ +static struct DenomKeyPair * +create_denom_key_pair (unsigned int size, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_Amount *value, + const struct TALER_Amount *fee_withdraw, + const struct TALER_Amount *fee_deposit, + const struct TALER_Amount *fee_refresh) +{ + struct DenomKeyPair *dkp; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki; + + dkp = GNUNET_new (struct DenomKeyPair); + dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size); + GNUNET_assert (NULL != dkp->priv.rsa_private_key); + dkp->pub.rsa_public_key + = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv.rsa_private_key); + + /* Using memset() as fields like master key and signature + are not properly initialized for this test. */ + memset (&dki, + 0, + sizeof (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation)); + dki.denom_pub = dkp->pub; + dki.issue.properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_UNIT_HOURS)); + dki.issue.properties.expire_spend = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add + (GNUNET_TIME_absolute_get (), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2))); + dki.issue.properties.expire_legal = GNUNET_TIME_absolute_hton + (GNUNET_TIME_absolute_add + (GNUNET_TIME_absolute_get (), + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3))); + TALER_amount_hton (&dki.issue.properties.value, value); + TALER_amount_hton (&dki.issue.properties.fee_withdraw, fee_withdraw); + TALER_amount_hton (&dki.issue.properties.fee_deposit, fee_deposit); + TALER_amount_hton (&dki.issue.properties.fee_refresh, fee_refresh); + GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key, + &dki.issue.properties.denom_hash); + if (GNUNET_OK != + plugin->insert_denomination_info (plugin->cls, + session, + &dki.denom_pub, + &dki.issue)) + { + GNUNET_break(0); + destroy_denom_key_pair (dkp); + return NULL; + } + return dkp; +} + +static struct TALER_Amount value; +static struct TALER_Amount fee_withdraw; +static struct TALER_Amount fee_deposit; +static struct TALER_Amount fee_refresh; +static struct TALER_Amount amount_with_fee; + +static void +free_refresh_commit_coins_array(struct TALER_EXCHANGEDB_RefreshCommitCoin + *commit_coins, + unsigned int size) +{ + unsigned int cnt; + struct TALER_EXCHANGEDB_RefreshCommitCoin *ccoin; + struct TALER_RefreshLinkEncrypted *rlink; + + for (cnt = 0; cnt < size; cnt++) + { + ccoin = &commit_coins[cnt]; + GNUNET_free_non_null (ccoin->coin_ev); + rlink = (struct TALER_RefreshLinkEncrypted *) ccoin->refresh_link; + GNUNET_free_non_null (rlink); + } + GNUNET_free (commit_coins); +} + +#define MELT_NEW_COINS 5 + +static int +test_refresh_commit_coins (struct TALER_EXCHANGEDB_Session *session, + struct TALER_EXCHANGEDB_RefreshSession *refresh_session, + const struct GNUNET_HashCode *session_hash) +{ + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins; + struct TALER_EXCHANGEDB_RefreshCommitCoin *ret_commit_coins; + struct TALER_EXCHANGEDB_RefreshCommitCoin *a_ccoin; + struct TALER_RefreshLinkEncrypted *a_rlink; + struct TALER_EXCHANGEDB_RefreshCommitCoin *b_ccoin; + struct TALER_RefreshLinkEncrypted *b_rlink; + size_t size; + unsigned int cnt; + uint16_t cnc_index; + int ret; + + #define COIN_ENC_MAX_SIZE 512 + ret = GNUNET_SYSERR; + ret_commit_coins = NULL; + commit_coins = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_EXCHANGEDB_RefreshCommitCoin); + cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32 + (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX)); + for (cnt=0; cnt < MELT_NEW_COINS; cnt++) + { + struct TALER_EXCHANGEDB_RefreshCommitCoin *ccoin; + struct TALER_RefreshLinkEncrypted *rlink; + ccoin = &commit_coins[cnt]; + size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + COIN_ENC_MAX_SIZE); + rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size); + ccoin->refresh_link = rlink; + ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64 + (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE); + ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + ccoin->coin_ev, + ccoin->coin_ev_size); + rlink->blinding_key_enc_size = size; + RND_BLK (&rlink->coin_priv_enc); + rlink->blinding_key_enc = (const char *) &rlink[1]; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + (void *)rlink->blinding_key_enc, + rlink->blinding_key_enc_size); + } + FAILIF (GNUNET_OK != + plugin->insert_refresh_commit_coins (plugin->cls, + session, + session_hash, + cnc_index, + MELT_NEW_COINS, + commit_coins)); + ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_EXCHANGEDB_RefreshCommitCoin); + FAILIF (GNUNET_OK != + plugin->get_refresh_commit_coins (plugin->cls, + session, + session_hash, + cnc_index, + MELT_NEW_COINS, + ret_commit_coins)); + /* compare the refresh commit coin arrays */ + for (cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + a_ccoin = &commit_coins[cnt]; + b_ccoin = &ret_commit_coins[cnt]; + FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size); + FAILIF (0 != memcmp (a_ccoin->coin_ev, + a_ccoin->coin_ev, + a_ccoin->coin_ev_size)); + a_rlink = a_ccoin->refresh_link; + b_rlink = b_ccoin->refresh_link; + FAILIF (a_rlink->blinding_key_enc_size != b_rlink->blinding_key_enc_size); + FAILIF (0 != memcmp (a_rlink->blinding_key_enc, + b_rlink->blinding_key_enc, + a_rlink->blinding_key_enc_size)); + FAILIF (0 != memcmp (a_rlink->coin_priv_enc, + b_rlink->coin_priv_enc, + sizeof (a_rlink->coin_priv_enc))); + } + ret = GNUNET_OK; + + drop: + if (NULL != ret_commit_coins) + free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS); + if (NULL != commit_coins) + free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS); + return ret; +} + +/** + * Function to test melting of coins as part of a refresh session + * + * @param session the database session + * @param refresh_session the refresh session + * @return #GNUNET_OK if everything went well; #GNUNET_SYSERR if not + */ +static int +test_melting (struct TALER_EXCHANGEDB_Session *session) +{ +#define MELT_OLD_COINS 10 + struct TALER_EXCHANGEDB_RefreshSession refresh_session; + struct TALER_EXCHANGEDB_RefreshSession ret_refresh_session; + struct GNUNET_HashCode session_hash; + struct DenomKeyPair *dkp; + struct DenomKeyPair **new_dkp; + /* struct TALER_CoinPublicInfo *coins; */ + struct TALER_EXCHANGEDB_RefreshMelt *melts; + struct TALER_DenominationPublicKey *new_denom_pubs; + struct TALER_DenominationPublicKey *ret_denom_pubs; + unsigned int cnt; + int ret; + + ret = GNUNET_SYSERR; + RND_BLK (&refresh_session); + RND_BLK (&session_hash); + melts = NULL; + dkp = NULL; + new_dkp = NULL; + new_denom_pubs = NULL; + ret_denom_pubs = NULL; + /* create and test a refresh session */ + refresh_session.num_oldcoins = MELT_OLD_COINS; + refresh_session.num_newcoins = 1; + refresh_session.noreveal_index = 1; + FAILIF (GNUNET_OK != plugin->create_refresh_session (plugin->cls, + session, + &session_hash, + &refresh_session)); + FAILIF (GNUNET_OK != plugin->get_refresh_session (plugin->cls, + session, + &session_hash, + &ret_refresh_session)); + FAILIF (0 != memcmp (&ret_refresh_session, + &refresh_session, + sizeof (refresh_session))); + + /* create a denomination (value: 1; fraction: 100) */ + dkp = create_denom_key_pair (512, session, + &value, + &fee_withdraw, + &fee_deposit, + &fee_refresh); + /* create MELT_OLD_COINS number of refresh melts */ + melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_EXCHANGEDB_RefreshMelt); + for (cnt=0; cnt < MELT_OLD_COINS; cnt++) + { + RND_BLK (&melts[cnt].coin.coin_pub); + melts[cnt].coin.denom_sig.rsa_signature = + GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key, + &melts[cnt].coin.coin_pub, + sizeof (melts[cnt].coin.coin_pub)); + melts[cnt].coin.denom_pub = dkp->pub; + RND_BLK (&melts[cnt].coin_sig); + melts[cnt].session_hash = session_hash; + melts[cnt].amount_with_fee = amount_with_fee; + melts[cnt].melt_fee = fee_refresh; + FAILIF (GNUNET_OK != plugin->insert_refresh_melt (plugin->cls, + session, + cnt, + &melts[cnt])); + } + for (cnt = 0; cnt < MELT_OLD_COINS; cnt++) + { + struct TALER_EXCHANGEDB_RefreshMelt ret_melt; + FAILIF (GNUNET_OK != plugin->get_refresh_melt (plugin->cls, + session, + &session_hash, + cnt, + &ret_melt)); + FAILIF (0 != GNUNET_CRYPTO_rsa_signature_cmp + (ret_melt.coin.denom_sig.rsa_signature, + melts[cnt].coin.denom_sig.rsa_signature)); + FAILIF (0 != memcmp (&ret_melt.coin.coin_pub, + &melts[cnt].coin.coin_pub, + sizeof (ret_melt.coin.coin_pub))); + FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp + (ret_melt.coin.denom_pub.rsa_public_key, + melts[cnt].coin.denom_pub.rsa_public_key)); + FAILIF (0 != memcmp (&ret_melt.coin_sig, + &melts[cnt].coin_sig, + sizeof (ret_melt.coin_sig))); + FAILIF (0 != memcmp (&ret_melt.session_hash, + &melts[cnt].session_hash, + sizeof (ret_melt.session_hash))); + FAILIF (0 != TALER_amount_cmp (&ret_melt.amount_with_fee, + &melts[cnt].amount_with_fee)); + FAILIF (0 != TALER_amount_cmp (&ret_melt.melt_fee, + &melts[cnt].melt_fee)); + GNUNET_CRYPTO_rsa_signature_free (ret_melt.coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (ret_melt.coin.denom_pub.rsa_public_key); + } + new_dkp = GNUNET_new_array (MELT_NEW_COINS, struct DenomKeyPair *); + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + for (cnt=0; cnt < MELT_NEW_COINS; cnt++) + { + new_dkp[cnt] = create_denom_key_pair (128, session, + &value, + &fee_withdraw, + &fee_deposit, + &fee_refresh); + new_denom_pubs[cnt]=new_dkp[cnt]->pub; + } + FAILIF (GNUNET_OK != plugin->insert_refresh_order (plugin->cls, + session, + &session_hash, + MELT_NEW_COINS, + new_denom_pubs)); + ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + FAILIF (GNUNET_OK != plugin->get_refresh_order (plugin->cls, + session, + &session_hash, + MELT_NEW_COINS, + ret_denom_pubs)); + for (cnt=0; cnt < MELT_NEW_COINS; cnt++) + { + FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp + (ret_denom_pubs[cnt].rsa_public_key, + new_denom_pubs[cnt].rsa_public_key)); + } + FAILIF (GNUNET_OK != + test_refresh_commit_coins (session, + &refresh_session, + &session_hash)); + + ret = GNUNET_OK; + + drop: + if (NULL != dkp) + destroy_denom_key_pair (dkp); + if (NULL != melts) + { + for (cnt = 0; cnt < MELT_OLD_COINS; cnt++) + GNUNET_CRYPTO_rsa_signature_free (melts[cnt].coin.denom_sig.rsa_signature); + GNUNET_free (melts); + } + for (cnt = 0; + (NULL != ret_denom_pubs) && (cnt < MELT_NEW_COINS) + && (NULL != ret_denom_pubs[cnt].rsa_public_key); + cnt++) + GNUNET_CRYPTO_rsa_public_key_free (ret_denom_pubs[cnt].rsa_public_key); + GNUNET_free_non_null (ret_denom_pubs); + GNUNET_free_non_null (new_denom_pubs); + for (cnt = 0; + (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); + cnt++) + destroy_denom_key_pair (new_dkp[cnt]); + GNUNET_free_non_null (new_dkp); + return ret; +} + + +/** + * Callback that should never be called. + */ +static void +cb_wt_never (void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_value, + const struct TALER_Amount *coin_fee) +{ + GNUNET_assert (0); /* this statement should be unreachable */ +} + + +/** + * Callback that should never be called. + */ +static void +cb_wtid_never (void *cls, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_Amount *coin_contribution, + const struct TALER_Amount *coin_fee, + struct GNUNET_TIME_Absolute execution_time) +{ + GNUNET_assert (0); +} + + +static struct TALER_MerchantPublicKeyP merchant_pub_wt; +static struct GNUNET_HashCode h_wire_wt; +static struct GNUNET_HashCode h_contract_wt; +static uint64_t transaction_id_wt; +static struct TALER_CoinSpendPublicKeyP coin_pub_wt; +static struct TALER_Amount coin_value_wt; +static struct TALER_Amount coin_fee_wt; +static struct TALER_Amount transfer_value_wt; +static struct GNUNET_TIME_Absolute execution_time_wt; +static struct TALER_WireTransferIdentifierRawP wtid_wt; + + +/** + * Callback that should be called with the WT data. + */ +static void +cb_wt_check (void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_value, + const struct TALER_Amount *coin_fee) +{ + GNUNET_assert (cls == &cb_wt_never); + GNUNET_assert (0 == memcmp (merchant_pub, + &merchant_pub_wt, + sizeof (struct TALER_MerchantPublicKeyP))); + GNUNET_assert (0 == memcmp (h_wire, + &h_wire_wt, + sizeof (struct GNUNET_HashCode))); + GNUNET_assert (0 == memcmp (h_contract, + &h_contract_wt, + sizeof (struct GNUNET_HashCode))); + GNUNET_assert (transaction_id == transaction_id_wt); + GNUNET_assert (0 == memcmp (coin_pub, + &coin_pub_wt, + sizeof (struct TALER_CoinSpendPublicKeyP))); + GNUNET_assert (0 == TALER_amount_cmp (coin_value, + &coin_value_wt)); + GNUNET_assert (0 == TALER_amount_cmp (coin_fee, + &coin_fee_wt)); +} + + +/** + * Callback that should be called with the WT data. + */ +static void +cb_wtid_check (void *cls, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_Amount *coin_contribution, + const struct TALER_Amount *coin_fee, + struct GNUNET_TIME_Absolute execution_time) +{ + GNUNET_assert (cls == &cb_wtid_never); + GNUNET_assert (0 == memcmp (wtid, + &wtid_wt, + sizeof (struct TALER_WireTransferIdentifierRawP))); + GNUNET_assert (execution_time.abs_value_us == + execution_time_wt.abs_value_us); + GNUNET_assert (0 == TALER_amount_cmp (coin_contribution, + &coin_value_wt)); + GNUNET_assert (0 == TALER_amount_cmp (coin_fee, + &coin_fee_wt)); +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct TALER_EXCHANGEDB_Session *session; + struct TALER_ReservePublicKeyP reserve_pub; + struct DenomKeyPair *dkp; + struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; + struct TALER_EXCHANGEDB_CollectableBlindcoin cbc2; + struct TALER_EXCHANGEDB_ReserveHistory *rh; + struct TALER_EXCHANGEDB_ReserveHistory *rh_head; + struct TALER_EXCHANGEDB_BankTransfer *bt; + struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw; + struct TALER_EXCHANGEDB_Deposit deposit; + struct TALER_EXCHANGEDB_Deposit deposit2; + struct TALER_WireTransferIdentifierRawP wtid; + json_t *wire; + json_t *just; + const char * const json_wire_str = + "{ \"type\":\"SEPA\", \ +\"IBAN\":\"DE67830654080004822650\", \ +\"name\":\"GNUnet e.V.\", \ +\"bic\":\"GENODEF1SLR\", \ +\"edate\":\"1449930207000\", \ +\"r\":123456789, \ +\"address\": \"foobar\"}"; + unsigned int cnt; + + dkp = NULL; + rh = NULL; + wire = NULL; + session = NULL; + ZR_BLK (&cbc); + ZR_BLK (&cbc2); + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + result = 1; + return; + } + if (GNUNET_OK != + plugin->create_tables (plugin->cls, + GNUNET_YES)) + { + result = 2; + goto drop; + } + if (NULL == + (session = plugin->get_session (plugin->cls, + GNUNET_YES))) + { + result = 3; + goto drop; + } + RND_BLK (&reserve_pub); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fee_withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fee_deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fee_refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &amount_with_fee)); + + result = 4; + just = json_loads ("{ \"justification\":\"1\" }", 0, NULL); + FAILIF (GNUNET_OK != + plugin->reserves_in_insert (plugin->cls, + session, + &reserve_pub, + &value, + GNUNET_TIME_absolute_get (), + just)); + json_decref (just); + FAILIF (GNUNET_OK != + check_reserve (session, + &reserve_pub, + value.value, + value.fraction, + value.currency)); + just = json_loads ("{ \"justification\":\"2\" }", 0, NULL); + FAILIF (GNUNET_OK != + plugin->reserves_in_insert (plugin->cls, + session, + &reserve_pub, + &value, + GNUNET_TIME_absolute_get (), + just)); + json_decref (just); + FAILIF (GNUNET_OK != + check_reserve (session, + &reserve_pub, + value.value * 2, + value.fraction * 2, + value.currency)); + dkp = create_denom_key_pair (1024, session, + &value, + &fee_withdraw, + &fee_deposit, + &fee_refresh); + RND_BLK(&cbc.h_coin_envelope); + RND_BLK(&cbc.reserve_sig); + cbc.denom_pub = dkp->pub; + cbc.sig.rsa_signature + = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key, + &cbc.h_coin_envelope, + sizeof (cbc.h_coin_envelope)); + cbc.reserve_pub = reserve_pub; + cbc.amount_with_fee = value; + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee)); + FAILIF (GNUNET_OK != + plugin->insert_withdraw_info (plugin->cls, + session, + &cbc)); + FAILIF (GNUNET_OK != + check_reserve (session, + &reserve_pub, + value.value, + value.fraction, + value.currency)); + FAILIF (GNUNET_YES != + plugin->get_withdraw_info (plugin->cls, + session, + &cbc.h_coin_envelope, + &cbc2)); + FAILIF (NULL == cbc2.denom_pub.rsa_public_key); + FAILIF (0 != memcmp (&cbc2.reserve_sig, + &cbc.reserve_sig, + sizeof (cbc2.reserve_sig))); + FAILIF (0 != memcmp (&cbc2.reserve_pub, + &cbc.reserve_pub, + sizeof (cbc2.reserve_pub))); + FAILIF (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope, + cbc2.sig.rsa_signature, + dkp->pub.rsa_public_key)); + rh = plugin->get_reserve_history (plugin->cls, + session, + &reserve_pub); + FAILIF (NULL == rh); + rh_head = rh; + for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++) + { + switch (rh_head->type) + { + case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: + bt = rh_head->details.bank; + FAILIF (0 != memcmp (&bt->reserve_pub, + &reserve_pub, + sizeof (reserve_pub))); + /* this is the amount we trasferred twice*/ + FAILIF (1 != bt->amount.value); + FAILIF (10 != bt->amount.fraction); + FAILIF (0 != strcmp (CURRENCY, bt->amount.currency)); + FAILIF (NULL == bt->wire); + break; + case TALER_EXCHANGEDB_RO_WITHDRAW_COIN: + withdraw = rh_head->details.withdraw; + FAILIF (0 != memcmp (&withdraw->reserve_pub, + &reserve_pub, + sizeof (reserve_pub))); + FAILIF (0 != memcmp (&withdraw->h_coin_envelope, + &cbc.h_coin_envelope, + sizeof (cbc.h_coin_envelope))); + break; + } + } + FAILIF (3 != cnt); + /* Tests for deposits */ + memset (&deposit, 0, sizeof (deposit)); + RND_BLK (&deposit.coin.coin_pub); + deposit.coin.denom_pub = dkp->pub; + deposit.coin.denom_sig = cbc.sig; + RND_BLK (&deposit.csig); + RND_BLK (&deposit.merchant_pub); + RND_BLK (&deposit.h_contract); + RND_BLK (&deposit.h_wire); + wire = json_loads (json_wire_str, 0, NULL); + deposit.wire = wire; + deposit.transaction_id = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + deposit.amount_with_fee = value; + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (CURRENCY, &deposit.deposit_fee)); + FAILIF (GNUNET_OK != + plugin->insert_deposit (plugin->cls, + session, &deposit)); + FAILIF (GNUNET_YES != + plugin->have_deposit (plugin->cls, + session, + &deposit)); + deposit2 = deposit; + deposit2.transaction_id++; /* should fail if transaction id is different */ + FAILIF (GNUNET_NO != + plugin->have_deposit (plugin->cls, + session, + &deposit2)); + deposit2.transaction_id = deposit.transaction_id; + RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */ + FAILIF (GNUNET_NO != + plugin->have_deposit (plugin->cls, + session, + &deposit2)); + deposit2.merchant_pub = deposit.merchant_pub; + RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */ + FAILIF (GNUNET_NO != + plugin->have_deposit (plugin->cls, + session, + &deposit2)); + FAILIF (GNUNET_OK != test_melting (session)); + + /* setup values for wire transfer aggregation data */ + memset (&wtid, 42, sizeof (wtid)); + memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt)); + memset (&h_wire_wt, 44, sizeof (h_wire_wt)); + memset (&h_contract_wt, 45, sizeof (h_contract_wt)); + memset (&coin_pub_wt, 46, sizeof (coin_pub_wt)); + transaction_id_wt = 47; + execution_time_wt = GNUNET_TIME_absolute_get (); + memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY "KUDOS:1.000010", + &coin_value_wt)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY "KUDOS:0.000010", + &coin_fee_wt)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY "KUDOS:1.000000", + &transfer_value_wt)); + + FAILIF (GNUNET_NO != + plugin->lookup_wire_transfer (plugin->cls, + session, + &wtid_wt, + &cb_wt_never, + NULL)); + FAILIF (GNUNET_NO != + plugin->wire_lookup_deposit_wtid (plugin->cls, + session, + &h_contract_wt, + &h_wire_wt, + &coin_pub_wt, + &merchant_pub_wt, + transaction_id_wt, + &cb_wtid_never, + NULL)); + /* insert WT data */ + FAILIF (GNUNET_OK != + plugin->insert_aggregation_tracking (plugin->cls, + session, + &wtid_wt, + &merchant_pub_wt, + &h_wire_wt, + &h_contract_wt, + transaction_id_wt, + execution_time_wt, + &coin_pub_wt, + &coin_value_wt, + &coin_fee_wt)); + FAILIF (GNUNET_OK != + plugin->lookup_wire_transfer (plugin->cls, + session, + &wtid_wt, + &cb_wt_check, + &cb_wt_never)); + FAILIF (GNUNET_OK != + plugin->wire_lookup_deposit_wtid (plugin->cls, + session, + &h_contract_wt, + &h_wire_wt, + &coin_pub_wt, + &merchant_pub_wt, + transaction_id_wt, + &cb_wtid_check, + &cb_wtid_never)); + result = 0; + + drop: + if (NULL != wire) + json_decref (wire); + if (NULL != rh) + plugin->free_reserve_history (plugin->cls, + rh); + rh = NULL; + if (NULL != session) + GNUNET_break (GNUNET_OK == + plugin->drop_temporary (plugin->cls, + session)); + if (NULL != dkp) + destroy_denom_key_pair (dkp); + if (NULL != cbc.sig.rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature); + if (NULL != cbc2.denom_pub.rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key); + if (NULL != cbc2.sig.rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature); + dkp = NULL; + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; +} + + +int +main (int argc, + char *const argv[]) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + char *argv2[] = { + "test-exchange-db-<plugin_name>", /* will be replaced later */ + "-c", "test-exchange-db-<plugin_name>.conf", /* will be replaced later */ + NULL, + }; + const char *plugin_name; + char *config_filename; + char *testname; + + result = -1; + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-exchange-db-%s", plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", testname); + argv2[0] = argv[0]; + argv2[2] = config_filename; + if (GNUNET_OK != + GNUNET_PROGRAM_run ((sizeof (argv2)/sizeof (char *)) - 1, argv2, + testname, + "Test cases for exchange database helper functions.", + options, &run, NULL)) + { + GNUNET_free (config_filename); + GNUNET_free (testname); + return 3; + } + GNUNET_free (config_filename); + GNUNET_free (testname); + return result; +} diff --git a/src/exchangedb/test_exchangedb_deposits.c b/src/exchangedb/test_exchangedb_deposits.c new file mode 100644 index 000000000..09c65b2b2 --- /dev/null +++ b/src/exchangedb/test_exchangedb_deposits.c @@ -0,0 +1,152 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange/test_exchange_deposits.c + * @brief testcase for exchange deposits + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ +#include "platform.h" +#include <libpq-fe.h> +#include <gnunet/gnunet_util_lib.h> +#include "taler_pq_lib.h" +#include "taler_exchangedb_lib.h" +#include "taler_exchangedb_plugin.h" + +#define EXCHANGE_CURRENCY "EUR" + +#define DB_URI "postgres:///taler" + +#define break_db_err(result) do { \ + GNUNET_break(0); \ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ + } while (0) + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Should we not interact with a temporary table? + */ +static int persistent; + +/** + * Testcase result + */ +static int result; + +/** + * The plugin. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + static const char wire[] = "{" + "\"type\":\"SEPA\"," + "\"IBAN\":\"DE67830654080004822650\"," + "\"NAME\":\"GNUNET E.V\"," + "\"BIC\":\"GENODEF1SRL\"" + "}"; + struct TALER_EXCHANGEDB_Deposit *deposit; + uint64_t transaction_id; + struct TALER_EXCHANGEDB_Session *session; + + deposit = NULL; + EXITIF (NULL == (plugin = TALER_EXCHANGEDB_plugin_load (cfg))); + EXITIF (GNUNET_OK != + plugin->create_tables (plugin->cls, + ! persistent)); + session = plugin->get_session (plugin->cls, + ! persistent); + EXITIF (NULL == session); + deposit = GNUNET_malloc (sizeof (struct TALER_EXCHANGEDB_Deposit) + sizeof (wire)); + /* Makeup a random coin public key */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + deposit, + sizeof (struct TALER_EXCHANGEDB_Deposit)); + /* Makeup a random 64bit transaction ID */ + transaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + deposit->transaction_id = GNUNET_htonll (transaction_id); + /* Random amount */ + deposit->amount_with_fee.value = + htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); + deposit->amount_with_fee.fraction = + htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); + GNUNET_assert (strlen (EXCHANGE_CURRENCY) < sizeof (deposit->amount_with_fee.currency)); + strcpy (deposit->amount_with_fee.currency, EXCHANGE_CURRENCY); + /* Copy wireformat */ + deposit->wire = json_loads (wire, 0, NULL); + EXITIF (GNUNET_OK != + plugin->insert_deposit (plugin->cls, + session, + deposit)); + EXITIF (GNUNET_OK != + plugin->have_deposit (plugin->cls, + session, + deposit)); + result = GNUNET_OK; + + EXITIF_exit: + GNUNET_free_non_null (deposit); + if (NULL != plugin) + { + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; + } +} + + +int +main (int argc, + char *const argv[]) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'T', "persist", NULL, + gettext_noop ("Use a persistent database table instead of a temporary one"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &persistent}, + GNUNET_GETOPT_OPTION_END + }; + + + persistent = GNUNET_NO; + result = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "test-exchange-deposits", + "testcase for exchange deposits", + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} diff --git a/src/exchangedb/test_exchangedb_keyio.c b/src/exchangedb/test_exchangedb_keyio.c new file mode 100644 index 000000000..2485da8ae --- /dev/null +++ b/src/exchangedb/test_exchangedb_keyio.c @@ -0,0 +1,85 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e. V. (and other contributing authors) + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange/test_exchange_common.c + * @brief test cases for some functions in exchange/exchange_common.c + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ +#include "platform.h" +#include "gnunet/gnunet_util_lib.h" +#include "taler_signatures.h" +#include "taler_exchangedb_lib.h" + +#define RSA_KEY_SIZE 1024 + + +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +int +main (int argc, + const char *const argv[]) +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki; + char *enc; + size_t enc_size; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki_read; + char *enc_read; + size_t enc_read_size; + char *tmpfile; + int ret; + + ret = 1; + enc = NULL; + enc_read = NULL; + tmpfile = NULL; + dki.denom_priv.rsa_private_key = NULL; + dki_read.denom_priv.rsa_private_key = NULL; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &dki.issue.signature, + sizeof (struct TALER_MasterSignatureP)); + dki.denom_priv.rsa_private_key + = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE); + enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv.rsa_private_key, + &enc); + EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_exchange_common"))); + EXITIF (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_write (tmpfile, &dki)); + EXITIF (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_read (tmpfile, &dki_read)); + enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key, + &enc_read); + EXITIF (enc_size != enc_read_size); + EXITIF (0 != memcmp (enc, + enc_read, + enc_size)); + ret = 0; + + EXITIF_exit: + GNUNET_free_non_null (enc); + if (NULL != tmpfile) + { + (void) unlink (tmpfile); + GNUNET_free (tmpfile); + } + GNUNET_free_non_null (enc_read); + if (NULL != dki.denom_priv.rsa_private_key) + GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv.rsa_private_key); + if (NULL != dki_read.denom_priv.rsa_private_key) + GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv.rsa_private_key); + return ret; +} diff --git a/src/exchangedb/test_perf_taler_exchangedb.c b/src/exchangedb/test_perf_taler_exchangedb.c new file mode 100644 index 000000000..a4ec9591d --- /dev/null +++ b/src/exchangedb/test_perf_taler_exchangedb.c @@ -0,0 +1,182 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> + */ +/** + * @file exchangedb/test_perf_taler_exchangedb.c + * @brief Exchange database performance analysis + * @author Nicolas Fournier + */ +#include "platform.h" +#include "perf_taler_exchangedb_interpreter.h" +#include "perf_taler_exchangedb_init.h" + + +#define NB_DENOMINATION_INIT 2 +#define NB_DENOMINATION_SAVE 2 + +#define NB_RESERVE_INIT 4 +#define NB_RESERVE_SAVE 1 + +#define NB_DEPOSIT_INIT 1 +#define NB_DEPOSIT_SAVE 1 + +#define NB_WITHDRAW_INIT 1 +#define NB_WITHDRAW_SAVE 1 + +/** + * Allocate, copies and free all the data used in the interpreter + * Used to check for memory leaks + */ +static void +test_allocate () +{ + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, *dki_copy; + struct PERF_TALER_EXCHANGEDB_Reserve *reserve, *reserve_copy; + struct PERF_TALER_EXCHANGEDB_Coin *coin, *coin_copy; + struct TALER_EXCHANGEDB_Deposit *deposit, *deposit_copy; + + dki = PERF_TALER_EXCHANGEDB_denomination_init (); + reserve = PERF_TALER_EXCHANGEDB_reserve_init (); + coin = PERF_TALER_EXCHANGEDB_coin_init (dki, + reserve); + deposit = PERF_TALER_EXCHANGEDB_deposit_init (coin); + + dki_copy = PERF_TALER_EXCHANGEDB_denomination_copy (dki); + reserve_copy = PERF_TALER_EXCHANGEDB_reserve_copy (reserve); + coin_copy = PERF_TALER_EXCHANGEDB_coin_copy (coin); + deposit_copy = PERF_TALER_EXCHANGEDB_deposit_copy (deposit); + + PERF_TALER_EXCHANGEDB_denomination_free (dki); + PERF_TALER_EXCHANGEDB_denomination_free (dki_copy); + PERF_TALER_EXCHANGEDB_reserve_free (reserve); + PERF_TALER_EXCHANGEDB_reserve_free (reserve_copy); + PERF_TALER_EXCHANGEDB_coin_free (coin); + PERF_TALER_EXCHANGEDB_coin_free (coin_copy); + PERF_TALER_EXCHANGEDB_deposit_free (deposit); + PERF_TALER_EXCHANGEDB_deposit_free (deposit_copy); +} + +/** + * Runs the performances tests for the exchange database + * and logs the results using Gauger + */ +int +main (int argc, char ** argv) +{ + int ret = 0; + struct PERF_TALER_EXCHANGEDB_Cmd init[] = + { + PERF_TALER_EXCHANGEDB_INIT_CMD_END ("init") + }; + struct PERF_TALER_EXCHANGEDB_Cmd benchmark[] = + { + // Denomination used to create coins + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("00 - Start of interpreter"), + + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("01 - denomination loop", + NB_DENOMINATION_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("01 - start transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", + "01 - denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("01 - commit transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", + "01 - denomination loop", + "01 - denomination", + NB_DENOMINATION_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("01 - denomination loop end", + "01 - denomination loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("01 - init denomination complete"), + // End of initialization + // Reserve initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("02 - init reserve loop", + NB_RESERVE_INIT), + + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_RESERVE ("02 - insert", + "02 - reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", + "02 - init reserve loop", + "02 - reserve", + NB_RESERVE_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("02 - init reserve end loop", + "02 - init reserve loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("02 - reserve init complete"), + // End reserve init + // Withdrawal initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("03 - init withdraw loop", + NB_WITHDRAW_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("03 - start transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", + "03 - init withdraw loop", + "01 - save denomination"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", + "03 - init withdraw loop", + "02 - save reserve"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", + "03 - denomination load", + "03 - reserve load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert withdraw", + "03 - withdraw"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("03 - commit transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("03 - coin array", + "03 - init withdraw loop", + "03 - withdraw", + NB_WITHDRAW_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("03 - withdraw init end loop", + "03 - init withdraw loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("03 - withdraw init complete"), + //End of withdrawal initialization + //Deposit initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("04 - time start"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOOP ("04 - deposit init loop", + NB_DEPOSIT_INIT), + PERF_TALER_EXCHANGEDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_LOAD_ARRAY ("04 - coin load", + "04 - deposit init loop", + "03 - coin array"), + PERF_TALER_EXCHANGEDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit", + "04 - coin load"), + PERF_TALER_EXCHANGEDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert deposit", + "04 - deposit"), + PERF_TALER_EXCHANGEDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"), + PERF_TALER_EXCHANGEDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", + "04 - deposit init loop", + "04 - deposit", + NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_END_LOOP ("04 - deposit init loop end", + "04 - deposit init loop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GET_TIME ("04 - time stop"), + PERF_TALER_EXCHANGEDB_INIT_CMD_GAUGER ("04 - gauger", + "04 - time start", + "04 - time stop", + "TEST", + "time to insert a deposit", + "deposit/sec", + NB_DEPOSIT_SAVE), + PERF_TALER_EXCHANGEDB_INIT_CMD_DEBUG ("04 - deposit init complete"), + // End of deposit initialization + PERF_TALER_EXCHANGEDB_INIT_CMD_END ("end"), + }; + + test_allocate (); + ret = PERF_TALER_EXCHANGEDB_run_benchmark ("test-perf-taler-exchangedb", + "./test-exchange-db-postgres.conf", + init, + benchmark); + if (GNUNET_SYSERR == ret) + return 1; + return 0; +} diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 4d7ae3cb2..6f7f53acb 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -16,9 +16,9 @@ talerinclude_HEADERS = \ taler_crypto_lib.h \ taler_json_lib.h \ taler_util.h \ - taler_mint_service.h \ - taler_mintdb_lib.h \ - taler_mintdb_plugin.h \ + taler_exchange_service.h \ + taler_exchangedb_lib.h \ + taler_exchangedb_plugin.h \ taler_pq_lib.h \ taler_signatures.h \ taler_wire_lib.h \ diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 6056270fa..e948fa28a 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -140,23 +140,23 @@ struct TALER_TransferPrivateKeyP /** - * @brief Type of online public keys used by the mint to sign + * @brief Type of online public keys used by the exchange to sign * messages. */ -struct TALER_MintPublicKeyP +struct TALER_ExchangePublicKeyP { /** - * Taler uses EdDSA for online mint message signing. + * Taler uses EdDSA for online exchange message signing. */ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub; }; /** - * @brief Type of online public keys used by the mint to + * @brief Type of online public keys used by the exchange to * sign messages. */ -struct TALER_MintPrivateKeyP +struct TALER_ExchangePrivateKeyP { /** * Taler uses EdDSA for online signatures sessions. @@ -166,9 +166,9 @@ struct TALER_MintPrivateKeyP /** - * @brief Type of signatures used by the mint to sign messages online. + * @brief Type of signatures used by the exchange to sign messages online. */ -struct TALER_MintSignatureP +struct TALER_ExchangeSignatureP { /** * Taler uses EdDSA for online signatures sessions. @@ -178,7 +178,7 @@ struct TALER_MintSignatureP /** - * @brief Type of the offline master public key used by the mint. + * @brief Type of the offline master public key used by the exchange. */ struct TALER_MasterPublicKeyP { @@ -214,7 +214,7 @@ struct TALER_AuditorSignatureP /** - * @brief Type of the offline master public keys used by the mint. + * @brief Type of the offline master public keys used by the exchange. */ struct TALER_MasterPrivateKeyP { @@ -226,7 +226,7 @@ struct TALER_MasterPrivateKeyP /** - * @brief Type of signatures by the offline master public key used by the mint. + * @brief Type of signatures by the offline master public key used by the exchange. */ struct TALER_MasterSignatureP { @@ -464,8 +464,8 @@ struct TALER_WireTransferIdentifierRawP /** * Binary information encoded in Crockford's Base32 in wire transfer * subjects of transfers from Taler to a merchant. The actual value - * is chosen by the mint and has no particular semantics, other than - * being unique so that the mint can lookup details about the wire + * is chosen by the exchange and has no particular semantics, other than + * being unique so that the exchange can lookup details about the wire * transfer when needed. */ struct TALER_WireTransferIdentifierP diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h new file mode 100644 index 000000000..566dec6f8 --- /dev/null +++ b/src/include/taler_exchange_service.h @@ -0,0 +1,1220 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/taler_exchange_service.h + * @brief C interface of libtalerexchange, a C library to use exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#ifndef _TALER_EXCHANGE_SERVICE_H +#define _TALER_EXCHANGE_SERVICE_H + +#include "taler_util.h" + +/* ********************* event loop *********************** */ + +/** + * @brief Handle to this library context. This is where the + * main event loop logic lives. + */ +struct TALER_EXCHANGE_Context; + + +/** + * Initialise a context. A context should be used for each thread and should + * not be shared among multiple threads. + * + * @return the context, NULL on error (failure to initialize) + */ +struct TALER_EXCHANGE_Context * +TALER_EXCHANGE_init (void); + + +/** + * Obtain the information for a select() call to wait until + * #TALER_EXCHANGE_perform() is ready again. Note that calling + * any other TALER_EXCHANGE-API may also imply that the library + * is again ready for #TALER_EXCHANGE_perform(). + * + * Basically, a client should use this API to prepare for select(), + * then block on select(), then call #TALER_EXCHANGE_perform() and then + * start again until the work with the context is done. + * + * This function will NOT zero out the sets and assumes that @a max_fd + * and @a timeout are already set to minimal applicable values. It is + * safe to give this API FD-sets and @a max_fd and @a timeout that are + * already initialized to some other descriptors that need to go into + * the select() call. + * + * @param ctx context to get the event loop information for + * @param read_fd_set will be set for any pending read operations + * @param write_fd_set will be set for any pending write operations + * @param except_fd_set is here because curl_multi_fdset() has this argument + * @param max_fd set to the highest FD included in any set; + * if the existing sets have no FDs in it, the initial + * value should be "-1". (Note that `max_fd + 1` will need + * to be passed to select().) + * @param timeout set to the timeout in milliseconds (!); -1 means + * no timeout (NULL, blocking forever is OK), 0 means to + * proceed immediately with #TALER_EXCHANGE_perform(). + */ +void +TALER_EXCHANGE_get_select_info (struct TALER_EXCHANGE_Context *ctx, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *except_fd_set, + int *max_fd, + long *timeout); + + +/** + * Run the main event loop for the Taler interaction. + * + * @param ctx the library context + */ +void +TALER_EXCHANGE_perform (struct TALER_EXCHANGE_Context *ctx); + + +/** + * Cleanup library initialisation resources. This function should be called + * after using this library to cleanup the resources occupied during library's + * initialisation. + * + * @param ctx the library context + */ +void +TALER_EXCHANGE_fini (struct TALER_EXCHANGE_Context *ctx); + + +/* ********************* /keys *********************** */ + + +/** + * List of possible options to be passed to + * #TALER_EXCHANGE_connect(). + */ +enum TALER_EXCHANGE_Option +{ + /** + * Terminator (end of option list). + */ + TALER_EXCHANGE_OPTION_END = 0 + +}; + + +/** + * @brief Exchange's signature key + */ +struct TALER_EXCHANGE_SigningPublicKey +{ + /** + * The signing public key + */ + struct TALER_ExchangePublicKeyP key; + + /** + * Validity start time + */ + struct GNUNET_TIME_Absolute valid_from; + + /** + * Validity expiration time + */ + struct GNUNET_TIME_Absolute valid_until; +}; + + +/** + * @brief Public information about a exchange's denomination key + */ +struct TALER_EXCHANGE_DenomPublicKey +{ + /** + * The public key + */ + struct TALER_DenominationPublicKey key; + + /** + * The hash of the public key. + */ + struct GNUNET_HashCode h_key; + + /** + * Timestamp indicating when the denomination key becomes valid + */ + struct GNUNET_TIME_Absolute valid_from; + + /** + * Timestamp indicating when the denomination key can’t be used anymore to + * withdraw new coins. + */ + struct GNUNET_TIME_Absolute withdraw_valid_until; + + /** + * Timestamp indicating when coins of this denomination become invalid. + */ + struct GNUNET_TIME_Absolute deposit_valid_until; + + /** + * When do signatures with this denomination key become invalid? + * After this point, these signatures cannot be used in (legal) + * disputes anymore, as the Exchange is then allowed to destroy its side + * of the evidence. @e expire_legal is expected to be significantly + * larger than @e expire_spend (by a year or more). + */ + struct GNUNET_TIME_Absolute expire_legal; + + /** + * The value of this denomination + */ + struct TALER_Amount value; + + /** + * The applicable fee for withdrawing a coin of this denomination + */ + struct TALER_Amount fee_withdraw; + + /** + * The applicable fee to spend a coin of this denomination + */ + struct TALER_Amount fee_deposit; + + /** + *The applicable fee to melt/refresh a coin of this denomination + */ + struct TALER_Amount fee_refresh; +}; + + +/** + * @brief Information we get from the exchange about auditors. + */ +struct TALER_EXCHANGE_AuditorInformation +{ + /** + * Public key of the auditing institution. + */ + struct TALER_AuditorPublicKeyP auditor_pub; + + /** + * URL of the auditing institution. The application must check that + * this is an acceptable auditor for its purpose and also verify + * that the @a auditor_pub matches the auditor's public key given at + * that website. We expect that in practice software is going to + * often ship with an initial list of accepted auditors, just like + * browsers ship with a CA root store. + * + * This field may be NULL. (#3987). + */ + const char *auditor_url; + + /** + * Number of denomination keys audited by this auditor. + */ + unsigned int num_denom_keys; + + /** + * Array of length @a denom_keys with the denomination + * keys audited by this auditor. Note that the array + * elements point to the same locations as the entries + * in the key's main `denom_keys` array. + */ + const struct TALER_EXCHANGE_DenomPublicKey **denom_keys; +}; + + +/** + * @brief Information about keys from the exchange. + */ +struct TALER_EXCHANGE_Keys +{ + + /** + * Long-term offline signing key of the exchange. + */ + struct TALER_MasterPublicKeyP master_pub; + + /** + * Array of the exchange's online signing keys. + */ + struct TALER_EXCHANGE_SigningPublicKey *sign_keys; + + /** + * Array of the exchange's denomination keys. + */ + struct TALER_EXCHANGE_DenomPublicKey *denom_keys; + + /** + * Array of the keys of the auditors of the exchange. + */ + struct TALER_EXCHANGE_AuditorInformation *auditors; + + /** + * Length of the @e sign_keys array. + */ + unsigned int num_sign_keys; + + /** + * Length of the @e denom_keys array. + */ + unsigned int num_denom_keys; + + /** + * Length of the @e auditors array. + */ + unsigned int num_auditors; + +}; + + +/** + * Function called with information about who is auditing + * a particular exchange and what key the exchange is using. + * + * @param cls closure + * @param keys information about the various keys used + * by the exchange + */ +typedef void +(*TALER_EXCHANGE_CertificationCallback) (void *cls, + const struct TALER_EXCHANGE_Keys *keys); + + +/** + * @brief Handle to the exchange. This is where we interact with + * a particular exchange and keep the per-exchange information. + */ +struct TALER_EXCHANGE_Handle; + + +/** + * Initialise a connection to the exchange. Will connect to the + * exchange and obtain information about the exchange's master public + * key and the exchange's auditor. The respective information will + * be passed to the @a cert_cb once available, and all future + * interactions with the exchange will be checked to be signed + * (where appropriate) by the respective master key. + * + * @param ctx the context + * @param url HTTP base URL for the exchange + * @param cert_cb function to call with the exchange's certification information + * @param cert_cb_cls closure for @a cert_cb + * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END. + * @return the exchange handle; NULL upon error + */ +struct TALER_EXCHANGE_Handle * +TALER_EXCHANGE_connect (struct TALER_EXCHANGE_Context *ctx, + const char *url, + TALER_EXCHANGE_CertificationCallback cert_cb, + void *cert_cb_cls, + ...); + + +/** + * Disconnect from the exchange. + * + * @param exchange the exchange handle + */ +void +TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange); + + +/** + * Obtain the keys from the exchange. + * + * @param exchange the exchange handle + * @return the exchange's key set + */ +const struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange); + + +/** + * Test if the given @a pub is a the current signing key from the exchange + * according to @a keys. + * + * @param keys the exchange's key set + * @param pub claimed current online signing key for the exchange + * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key + */ +int +TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_ExchangePublicKeyP *pub); + + +/** + * Obtain the denomination key details from the exchange. + * + * @param keys the exchange's key set + * @param pk public key of the denomination to lookup + * @return details about the given denomination key, NULL if the key is not + * found + */ +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_DenominationPublicKey *pk); + + +/** + * Obtain the denomination key details from the exchange. + * + * @param keys the exchange's key set + * @param hc hash of the public key of the denomination to lookup + * @return details about the given denomination key + */ +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys, + const struct GNUNET_HashCode *hc); + + +/* ********************* /wire *********************** */ + + +/** + * @brief A Wire format inquiry handle + */ +struct TALER_EXCHANGE_WireHandle; + + +/** + * Callbacks of this type are used to serve the result of submitting a + * wire format inquiry request to a exchange. + * + * The callback is invoked multiple times, once for each supported @a + * method. Finally, it is invoked one more time with cls/0/NULL/NULL + * to indicate the end of the iteration. If any request fails to + * generate a valid response from the exchange, @a http_status will also + * be zero and the iteration will also end. Thus, the iteration + * always ends with a final call with an @a http_status of 0. If the + * @a http_status is already 0 on the first call, then the response to + * the /wire request was invalid. Later, clients can tell the + * difference between @a http_status of 0 indicating a failed + * /wire/method request and a regular end of the iteration by @a + * method being non-NULL. If the exchange simply correctly asserts that + * it does not support any methods, @a method will be NULL but the @a + * http_status will be #MHD_HTTP_OK for the first call (followed by a + * cls/0/NULL/NULL call to signal the end of the iteration). + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param method wire format method supported, i.e. "test" or "sepa", or NULL + * if already the /wire request failed. + * @param obj the received JSON reply, if successful this should be the wire + * format details as provided by /wire/METHOD/, or NULL if the + * reply was not in JSON format (in this case, the client might + * want to do an HTTP request to /wire/METHOD/ with a browser to + * provide more information to the user about the @a method). + */ +typedef void +(*TALER_EXCHANGE_WireResultCallback) (void *cls, + unsigned int http_status, + const char *method, + json_t *obj); + + +/** + * Obtain information about a exchange's wire instructions. + * A exchange may provide wire instructions for creating + * a reserve. The wire instructions also indicate + * which wire formats merchants may use with the exchange. + * This API is typically used by a wallet for wiring + * funds, and possibly by a merchant to determine + * supported wire formats. + * + * Note that while we return the (main) response verbatim to the + * caller for further processing, we do already verify that the + * response is well-formed (i.e. that signatures included in the + * response are all valid). If the exchange's reply is not well-formed, + * we return an HTTP status code of zero to @a cb. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param wire_cb the callback to call when a reply for this request is available + * @param wire_cb_cls closure for the above callback + * @return a handle for this request + */ +struct TALER_EXCHANGE_WireHandle * +TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange, + TALER_EXCHANGE_WireResultCallback wire_cb, + void *wire_cb_cls); + + +/** + * Cancel a wire information request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param wh the wire information request handle + */ +void +TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh); + + +/* ********************* /deposit *********************** */ + + +/** + * @brief A Deposit Handle + */ +struct TALER_EXCHANGE_DepositHandle; + + +/** + * Callbacks of this type are used to serve the result of submitting a + * deposit permission request to a exchange. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param obj the received JSON reply, should be kept as proof (and, in case of errors, + * be forwarded to the customer) + */ +typedef void +(*TALER_EXCHANGE_DepositResultCallback) (void *cls, + unsigned int http_status, + json_t *obj); + + +/** + * Submit a deposit permission to the exchange and get the exchange's + * response. This API is typically used by a merchant. Note that + * while we return the response verbatim to the caller for further + * processing, we do already verify that the response is well-formed + * (i.e. that signatures included in the response are all valid). If + * the exchange's reply is not well-formed, we return an HTTP status code + * of zero to @a cb. + * + * We also verify that the @a coin_sig is valid for this deposit + * request, and that the @a ub_sig is a valid signature for @a + * coin_pub. Also, the @a exchange must be ready to operate (i.e. have + * finished processing the /keys reply). If either check fails, we do + * NOT initiate the transaction with the exchange and instead return NULL. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param amount the amount to be deposited + * @param wire_deadline execution date, until which the merchant would like the exchange to settle the balance (advisory, the exchange cannot be + * forced to settle in the past or upon very short notice, but of course a well-behaved exchange will limit aggregation based on the advice received) + * @param wire_details the merchant’s account details, in a format supported by the exchange + * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the exchange) + * @param coin_pub coin’s public key + * @param denom_pub denomination key with which the coin is signed + * @param denom_sig exchange’s unblinded signature of the coin + * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the exchange + * @param transaction_id transaction id for the transaction between merchant and customer + * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) + * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed) + * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_DepositHandle * +TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute wire_deadline, + json_t *wire_details, + const struct GNUNET_HashCode *h_contract, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_DenominationSignature *denom_sig, + const struct TALER_DenominationPublicKey *denom_pub, + struct GNUNET_TIME_Absolute timestamp, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Absolute refund_deadline, + const struct TALER_CoinSpendSignatureP *coin_sig, + TALER_EXCHANGE_DepositResultCallback cb, + void *cb_cls); + + +/** + * Cancel a deposit permission request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param deposit the deposit permission request handle + */ +void +TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit); + + +/* ********************* /reserve/status *********************** */ + + +/** + * @brief A /reserve/status Handle + */ +struct TALER_EXCHANGE_ReserveStatusHandle; + + +/** + * Ways how a reserve's balance may change. + */ +enum TALER_EXCHANGE_ReserveTransactionType { + + /** + * Deposit into the reserve. + */ + TALER_EXCHANGE_RTT_DEPOSIT, + + /** + * Withdrawal from the reserve. + */ + TALER_EXCHANGE_RTT_WITHDRAWAL + +}; + + +/** + * @brief Entry in the reserve's transaction history. + */ +struct TALER_EXCHANGE_ReserveHistory +{ + + /** + * Type of the transaction. + */ + enum TALER_EXCHANGE_ReserveTransactionType type; + + /** + * Amount transferred (in or out). + */ + struct TALER_Amount amount; + + /** + * Details depending on @e type. + */ + union { + + /** + * Transaction details for the incoming transaction. + */ + json_t *wire_in_details; + + /** + * Signature authorizing the withdrawal for outgoing transaction. + */ + json_t *out_authorization_sig; + + } details; + +}; + + +/** + * Callbacks of this type are used to serve the result of submitting a + * deposit permission request to a exchange. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param[in] json original response in JSON format (useful only for diagnostics) + * @param balance current balance in the reserve, NULL on error + * @param history_length number of entries in the transaction history, 0 on error + * @param history detailed transaction history, NULL on error + */ +typedef void +(*TALER_EXCHANGE_ReserveStatusResultCallback) (void *cls, + unsigned int http_status, + json_t *json, + const struct TALER_Amount *balance, + unsigned int history_length, + const struct TALER_EXCHANGE_ReserveHistory *history); + + +/** + * Submit a request to obtain the transaction history of a reserve + * from the exchange. Note that while we return the full response to the + * caller for further processing, we do already verify that the + * response is well-formed (i.e. that signatures included in the + * response are all valid and add up to the balance). If the exchange's + * reply is not well-formed, we return an HTTP status code of zero to + * @a cb. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param reserve_pub public key of the reserve to inspect + * @param cb the callback to call when a reply for this request is available + * @param cb_cls closure for the above callback + * @return a handle for this request; NULL if the inputs are invalid (i.e. + * signatures fail to verify). In this case, the callback is not called. + */ +struct TALER_EXCHANGE_ReserveStatusHandle * +TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_ReservePublicKeyP *reserve_pub, + TALER_EXCHANGE_ReserveStatusResultCallback cb, + void *cb_cls); + + +/** + * Cancel a withdraw status request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param wsh the withdraw status request handle + */ +void +TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh); + + +/* ********************* /reserve/withdraw *********************** */ + + +/** + * @brief A /reserve/withdraw Handle + */ +struct TALER_EXCHANGE_ReserveWithdrawHandle; + + +/** + * Callbacks of this type are used to serve the result of submitting a + * deposit permission request to a exchange. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param sig signature over the coin, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +typedef void +(*TALER_EXCHANGE_ReserveWithdrawResultCallback) (void *cls, + unsigned int http_status, + const struct TALER_DenominationSignature *sig, + json_t *full_response); + + +/** + * Withdraw a coin from the exchange using a /reserve/withdraw request. This + * API is typically used by a wallet. Note that to ensure that no + * money is lost in case of hardware failures, the caller must have + * committed (most of) the arguments to disk before calling, and be + * ready to repeat the request with the same arguments in case of + * failures. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param pk kind of coin to create + * @param reserve_priv private key of the reserve to withdraw from + * @param coin_priv where to store the coin's private key, + * caller must have committed this value to disk before the call (with @a pk) + * @param blinding_key where to store the coin's blinding key + * caller must have committed this value to disk before the call (with @a pk) + * @param res_cb the callback to call when the final result for this request is available + * @param res_cb_cls closure for @a res_cb + * @return NULL + * if the inputs are invalid (i.e. denomination key not with this exchange). + * In this case, the callback is not called. + */ +struct TALER_EXCHANGE_ReserveWithdrawHandle * +TALER_EXCHANGE_reserve_withdraw (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_EXCHANGE_DenomPublicKey *pk, + const struct TALER_ReservePrivateKeyP *reserve_priv, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + const struct TALER_DenominationBlindingKey *blinding_key, + TALER_EXCHANGE_ReserveWithdrawResultCallback res_cb, + void *res_cb_cls); + + +/** + * Cancel a withdraw status request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param sign the withdraw sign request handle + */ +void +TALER_EXCHANGE_reserve_withdraw_cancel (struct TALER_EXCHANGE_ReserveWithdrawHandle *sign); + + +/* ********************* /refresh/melt+reveal ***************************** */ + + +/** + * Melt (partially spent) coins to obtain fresh coins that are + * unlinkable to the original coin(s). Note that melting more + * than one coin in a single request will make those coins linkable, + * so the safest operation only melts one coin at a time. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, is operation does + * not actually initiate the request. Instead, it generates a buffer + * which the caller must store before proceeding with the actual call + * to #TALER_EXCHANGE_refresh_melt() that will generate the request. + * + * This function does verify that the given request data is internally + * consistent. However, the @a melts_sigs are only verified if @a + * check_sigs is set to #GNUNET_YES, as this may be relatively + * expensive and should be redundant. + * + * Aside from some non-trivial cryptographic operations that might + * take a bit of CPU time to complete, this function returns + * its result immediately and does not start any asynchronous + * processing. This function is also thread-safe. + * + * @param num_melts number of coins that are being melted (typically 1) + * @param melt_privs array of @a num_melts private keys of the coins to melt + * @param melt_amounts array of @a num_melts amounts specifying how much + * each coin will contribute to the melt (including fee) + * @param melt_sigs array of @a num_melts signatures affirming the + * validity of the public keys corresponding to the + * @a melt_privs private keys + * @param melt_pks array of @a num_melts denomination key information + * records corresponding to the @a melt_sigs + * validity of the keys + * @param check_sigs verify the validity of the signatures of @a melt_sigs + * @param fresh_pks_len length of the @a pks array + * @param fresh_pks array of @a pks_len denominations of fresh coins to create + * @param[out] res_size set to the size of the return value, or 0 on error + * @return NULL + * if the inputs are invalid (i.e. denomination key not with this exchange). + * Otherwise, pointer to a buffer of @a res_size to store persistently + * before proceeding to #TALER_EXCHANGE_refresh_melt(). + * Non-null results should be freed using #GNUNET_free(). + */ +char * +TALER_EXCHANGE_refresh_prepare (unsigned int num_melts, + const struct TALER_CoinSpendPrivateKeyP *melt_privs, + const struct TALER_Amount *melt_amounts, + const struct TALER_DenominationSignature *melt_sigs, + const struct TALER_EXCHANGE_DenomPublicKey *melt_pks, + int check_sigs, + unsigned int fresh_pks_len, + const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks, + size_t *res_size); + + +/* ********************* /refresh/melt ***************************** */ + +/** + * @brief A /refresh/melt Handle + */ +struct TALER_EXCHANGE_RefreshMeltHandle; + + +/** + * Callbacks of this type are used to notify the application about the + * result of the /refresh/melt stage. If successful, the @a noreveal_index + * should be committed to disk prior to proceeding #TALER_EXCHANGE_refresh_reveal(). + * + * @param cls closure + * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param noreveal_index choice by the exchange in the cut-and-choose protocol, + * UINT16_MAX on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +typedef void +(*TALER_EXCHANGE_RefreshMeltCallback) (void *cls, + unsigned int http_status, + uint16_t noreveal_index, + json_t *full_response); + + +/** + * Submit a melt request to the exchange and get the exchange's + * response. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, the provided + * argument should have been constructed using + * #TALER_EXCHANGE_refresh_prepare and committed to persistent storage + * prior to calling this function. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param refresh_data_length size of the @a refresh_data (returned + * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare()) + * @param refresh_data the refresh data as returned from + #TALER_EXCHANGE_refresh_prepare()) + * @param melt_cb the callback to call with the result + * @param melt_cb_cls closure for @a melt_cb + * @return a handle for this request; NULL if the argument was invalid. + * In this case, neither callback will be called. + */ +struct TALER_EXCHANGE_RefreshMeltHandle * +TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange, + size_t refresh_data_length, + const char *refresh_data, + TALER_EXCHANGE_RefreshMeltCallback melt_cb, + void *melt_cb_cls); + + +/** + * Cancel a refresh melt request. This function cannot be used + * on a request handle if the callback was already invoked. + * + * @param rmh the refresh handle + */ +void +TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh); + + +/* ********************* /refresh/reveal ***************************** */ + + +/** + * Callbacks of this type are used to return the final result of + * submitting a refresh request to a exchange. If the operation was + * successful, this function returns the signatures over the coins + * that were remelted. The @a coin_privs and @a sigs arrays give the + * coins in the same order (and should have the same length) in which + * the original request specified the respective denomination keys. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed + * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error + * @param sigs array of signature over @a num_coins coins, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +typedef void +(*TALER_EXCHANGE_RefreshRevealCallback) (void *cls, + unsigned int http_status, + + unsigned int num_coins, + const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_DenominationSignature *sigs, + json_t *full_response); + + +/** + * @brief A /refresh/reveal Handle + */ +struct TALER_EXCHANGE_RefreshRevealHandle; + + +/** + * Submit a /refresh/reval request to the exchange and get the exchange's + * response. + * + * This API is typically used by a wallet. Note that to ensure that + * no money is lost in case of hardware failures, the provided + * arguments should have been committed to persistent storage + * prior to calling this function. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param refresh_data_length size of the @a refresh_data (returned + * in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare()) + * @param refresh_data the refresh data as returned from + #TALER_EXCHANGE_refresh_prepare()) + * @param noreveal_index response from the exchange to the + * #TALER_EXCHANGE_refresh_melt() invocation + * @param reveal_cb the callback to call with the final result of the + * refresh operation + * @param reveal_cb_cls closure for the above callback + * @return a handle for this request; NULL if the argument was invalid. + * In this case, neither callback will be called. + */ +struct TALER_EXCHANGE_RefreshRevealHandle * +TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange, + size_t refresh_data_length, + const char *refresh_data, + uint16_t noreveal_index, + TALER_EXCHANGE_RefreshRevealCallback reveal_cb, + void *reveal_cb_cls); + + +/** + * Cancel a refresh reveal request. This function cannot be used + * on a request handle if the callback was already invoked. + * + * @param rrh the refresh reval handle + */ +void +TALER_EXCHANGE_refresh_reveal_cancel (struct TALER_EXCHANGE_RefreshRevealHandle *rrh); + + +/* ********************* /refresh/link ***************************** */ + + +/** + * @brief A /refresh/link Handle + */ +struct TALER_EXCHANGE_RefreshLinkHandle; + + +/** + * Callbacks of this type are used to return the final result of + * submitting a /refresh/link request to a exchange. If the operation was + * successful, this function returns the signatures over the coins + * that were created when the original coin was melted. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed + * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error + * @param sigs array of signature over @a num_coins coins, NULL on error + * @param pubs array of public keys for the @a sigs, NULL on error + * @param full_response full response from the exchange (for logging, in case of errors) + */ +typedef void +(*TALER_EXCHANGE_RefreshLinkCallback) (void *cls, + unsigned int http_status, + unsigned int num_coins, + const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_DenominationSignature *sigs, + const struct TALER_DenominationPublicKey *pubs, + json_t *full_response); + + +/** + * Submit a link request to the exchange and get the exchange's response. + * + * This API is typically not used by anyone, it is more a threat + * against those trying to receive a funds transfer by abusing the + * /refresh protocol. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param coin_priv private key to request link data for + * @param link_cb the callback to call with the useful result of the + * refresh operation the @a coin_priv was involved in (if any) + * @param link_cb_cls closure for @a link_cb + * @return a handle for this request + */ +struct TALER_EXCHANGE_RefreshLinkHandle * +TALER_EXCHANGE_refresh_link (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + TALER_EXCHANGE_RefreshLinkCallback link_cb, + void *link_cb_cls); + + +/** + * Cancel a refresh link request. This function cannot be used + * on a request handle if the callback was already invoked. + * + * @param rlh the refresh link handle + */ +void +TALER_EXCHANGE_refresh_link_cancel (struct TALER_EXCHANGE_RefreshLinkHandle *rlh); + + +/* ********************* /admin/add/incoming *********************** */ + + +/** + * @brief A /admin/add/incoming Handle + */ +struct TALER_EXCHANGE_AdminAddIncomingHandle; + + +/** + * Callbacks of this type are used to serve the result of submitting + * information about an incoming transaction to a exchange. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the exchange's reply is bogus (fails to follow the protocol) + * @param full_response full response from the exchange (for logging, in case of errors) + */ +typedef void +(*TALER_EXCHANGE_AdminAddIncomingResultCallback) (void *cls, + unsigned int http_status, + json_t *full_response); + + +/** + * Notify the exchange that we have received an incoming transaction + * which fills a reserve. Note that this API is an administrative + * API and thus not accessible to typical exchange clients, but only + * to the operators of the exchange. + * + * @param exchange the exchange handle; the exchange must be ready to operate + * @param reserve_pub public key of the reserve + * @param amount amount that was deposited + * @param execution_date when did we receive the amount + * @param wire wire details + * @param res_cb the callback to call when the final result for this request is available + * @param res_cb_cls closure for the above callback + * @return NULL + * if the inputs are invalid (i.e. invalid amount). + * In this case, the callback is not called. + */ +struct TALER_EXCHANGE_AdminAddIncomingHandle * +TALER_EXCHANGE_admin_add_incoming (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute execution_date, + const json_t *wire, + TALER_EXCHANGE_AdminAddIncomingResultCallback res_cb, + void *res_cb_cls); + + +/** + * Cancel an add incoming. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param aai the admin add incoming request handle + */ +void +TALER_EXCHANGE_admin_add_incoming_cancel (struct TALER_EXCHANGE_AdminAddIncomingHandle *aai); + + +/* ********************* /wire/deposits *********************** */ + +/** + * @brief A /wire/deposits Handle + */ +struct TALER_EXCHANGE_WireDepositsHandle; + + +/** + * Details for one of the /deposit operations that the + * exchange combined into a single wire transfer. + */ +struct TALER_WireDepositDetails +{ + /** + * Hash of the contract. + */ + struct GNUNET_HashCode h_contract; + + /** + * Which coin was deposited? + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Value of the deposit (including fee). + */ + struct TALER_Amount coin_value; + + /** + * Fee charged by the exchange for the deposit. + */ + struct TALER_Amount coin_fee; + + /** + * Merchant's transaction identifier. + */ + uint64_t transaction_id; + +}; + + +/** + * Function called with detailed wire transfer data, including all + * of the coin transactions that were combined into the wire transfer. + * + * @param cls closure + * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param json original json reply (may include signatures, those have then been + * validated already) + * @param wtid extracted wire transfer identifier, or NULL if the exchange could + * not provide any (set only if @a http_status is #MHD_HTTP_OK) + * @param total_amount total amount of the wire transfer, or NULL if the exchange could + * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) + * @param details_length length of the @a details array + * @param details array with details about the combined transactions + */ +typedef void +(*TALER_EXCHANGE_WireDepositsCallback)(void *cls, + unsigned int http_status, + json_t *json, + const struct GNUNET_HashCode *h_wire, + const struct TALER_Amount *total_amount, + unsigned int details_length, + const struct TALER_WireDepositDetails *details); + + +/** + * Query the exchange about which transactions were combined + * to create a wire transfer. + * + * @param exchange exchange to query + * @param wtid raw wire transfer identifier to get information about + * @param cb callback to call + * @param cb_cls closure for @a cb + * @return handle to cancel operation + */ +struct TALER_EXCHANGE_WireDepositsHandle * +TALER_EXCHANGE_wire_deposits (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_WireTransferIdentifierRawP *wtid, + TALER_EXCHANGE_WireDepositsCallback cb, + void *cb_cls); + + +/** + * Cancel wire deposits request. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param wdh the wire deposits request handle + */ +void +TALER_EXCHANGE_wire_deposits_cancel (struct TALER_EXCHANGE_WireDepositsHandle *wdh); + + +/* ********************* /deposit/wtid *********************** */ + + +/** + * @brief A /deposit/wtid Handle + */ +struct TALER_EXCHANGE_DepositWtidHandle; + + +/** + * Function called with detailed wire transfer data. + * + * @param cls closure + * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param json original json reply (may include signatures, those have then been + * validated already) + * @param wtid wire transfer identifier used by the exchange, NULL if exchange did not + * yet execute the transaction + * @param execution_time actual or planned execution time for the wire transfer + * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL) + */ +typedef void +(*TALER_EXCHANGE_DepositWtidCallback)(void *cls, + unsigned int http_status, + json_t *json, + const struct TALER_WireTransferIdentifierRawP *wtid, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_Amount *coin_contribution); + + +/** + * Obtain the wire transfer details for a given deposit. + * + * @param exchange the exchange to query + * @param merchant_priv the merchant's private key + * @param h_wire hash of merchant's wire transfer details + * @param h_contract hash of the contract + * @param coin_pub public key of the coin + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure for @a cb + * @return handle to abort request + */ +struct TALER_EXCHANGE_DepositWtidHandle * +TALER_EXCHANGE_deposit_wtid (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_MerchantPrivateKeyP *merchant_priv, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + uint64_t transaction_id, + TALER_EXCHANGE_DepositWtidCallback cb, + void *cb_cls); + + +/** + * Cancel deposit wtid request. This function cannot be used on a request + * handle if a response is already served for it. + * + * @param dwh the wire deposits request handle + */ +void +TALER_EXCHANGE_deposit_wtid_cancel (struct TALER_EXCHANGE_DepositWtidHandle *dwh); + + +#endif /* _TALER_EXCHANGE_SERVICE_H */ diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h new file mode 100644 index 000000000..347ad0650 --- /dev/null +++ b/src/include/taler_exchangedb_lib.h @@ -0,0 +1,291 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/taler_exchangedb_lib.h + * @brief IO operations for the exchange's private keys + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGEDB_LIB_H +#define TALER_EXCHANGEDB_LIB_H + +#include "taler_signatures.h" + +/** + * Subdirectroy under the exchange's base directory which contains + * the exchange's signing keys. + */ +#define TALER_EXCHANGEDB_DIR_SIGNING_KEYS "signkeys" + +/** + * Subdirectory under the exchange's base directory which contains + * the exchange's denomination keys. + */ +#define TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS "denomkeys" + +/** + * Subdirectory under the exchange's base directory which contains + * the exchange's auditing information. + */ +#define TALER_EXCHANGEDB_DIR_AUDITORS "auditors" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief On disk format used for a exchange signing key. Signing keys are used + * by the exchange to affirm its messages, but not to create coins. + * Includes the private key followed by the public information about + * the signing key. + */ +struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP +{ + /** + * Private key part of the exchange's signing key. + */ + struct TALER_ExchangePrivateKeyP signkey_priv; + + /** + * Public information about a exchange signing key. + */ + struct TALER_ExchangeSigningKeyValidityPS issue; +}; + + +/** + * Information about a denomination key. + */ +struct TALER_EXCHANGEDB_DenominationKeyInformationP +{ + + /** + * Signature over this struct to affirm the validity of the key. + */ + struct TALER_MasterSignatureP signature; + + /** + * Signed properties of the denomination key. + */ + struct TALER_DenominationKeyValidityPS properties; +}; + + +GNUNET_NETWORK_STRUCT_END + + +/** + * @brief All information about a denomination key (which is used to + * sign coins into existence). + */ +struct TALER_EXCHANGEDB_DenominationKeyIssueInformation +{ + /** + * The private key of the denomination. Will be NULL if the private + * key is not available (this is the case after the key has expired + * for signing coins, but is still valid for depositing coins). + */ + struct TALER_DenominationPrivateKey denom_priv; + + /** + * Decoded denomination public key (the hash of it is in + * @e issue, but we sometimes need the full public key as well). + */ + struct TALER_DenominationPublicKey denom_pub; + + /** + * Signed public information about a denomination key. + */ + struct TALER_EXCHANGEDB_DenominationKeyInformationP issue; +}; + + +/** + * @brief Iterator over signing keys. + * + * @param cls closure + * @param filename name of the file the key came from + * @param ski the sign key + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +typedef int +(*TALER_EXCHANGEDB_SigningKeyIterator)(void *cls, + const char *filename, + const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski); + + +/** + * Call @a it for each signing key found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_SIGNING_KEYS + * subdirectory + * @param it function to call on each signing key + * @param it_cls closure for @a it + * @return number of files found (may not match + * number of keys given to @a it as malformed + * files are simply skipped), -1 on error + */ +int +TALER_EXCHANGEDB_signing_keys_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_SigningKeyIterator it, + void *it_cls); + + + +/** + * @brief Iterator over denomination keys. + * + * @param cls closure + * @param dki the denomination key + * @param alias coin alias + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +typedef int +(*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls, + const char *alias, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + + +/** + * Call @a it for each denomination key found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS + * subdirectory + * @param it function to call on each denomination key found + * @param it_cls closure for @a it + * @return -1 on error, 0 if no files were found, otherwise + * a positive number (however, even with a positive + * number it is possible that @a it was never called + * as maybe none of the files were well-formed) + */ +int +TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_DenominationKeyIterator it, + void *it_cls); + + +/** + * Exports a denomination key to the given file. + * + * @param filename the file where to write the denomination key + * @param dki the denomination key + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. + */ +int +TALER_EXCHANGEDB_denomination_key_write (const char *filename, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + + +/** + * Import a denomination key from the given file. + * + * @param filename the file to import the key from + * @param[out] dki set to the imported denomination key + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_EXCHANGEDB_denomination_key_read (const char *filename, + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki); + + +/** + * @brief Iterator over auditor information. + * + * @param cls closure + * @param apub the auditor's public key + * @param mpub the exchange's public key (as expected by the auditor) + * @param dki_len length of @a asig and @a dki arrays + * @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len + * @param dki array of denomination coin data signed by the auditor, of length @a dki_len + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +typedef int +(*TALER_EXCHANGEDB_AuditorIterator)(void *cls, + const struct TALER_AuditorPublicKeyP *apub, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_DenominationKeyValidityPS *dki); + + +/** + * Call @a it with information for each auditor found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS + * subdirectory + * @param it function to call with auditor information + * @param it_cls closure for @a it + * @return -1 on error, 0 if no files were found, otherwise + * a positive number (however, even with a positive + * number it is possible that @a it was never called + * as maybe none of the files were well-formed) + */ +int +TALER_EXCHANGEDB_auditor_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_AuditorIterator it, + void *it_cls); + + +/** + * Write auditor information to the given file. + * + * @param filename the file where to write the auditor information to + * @param apub the auditor's public key + * @param asigs the auditor's signatures, array of length @a dki_len + * @param mpub the exchange's public key (as expected by the auditor) + * @param dki_len length of @a dki and @a asigs arrays + * @param dki array of denomination coin data signed by the auditor + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. + */ +int +TALER_EXCHANGEDB_auditor_write (const char *filename, + const struct TALER_AuditorPublicKeyP *apub, + const struct TALER_AuditorSignatureP *asigs, + const struct TALER_MasterPublicKeyP *mpub, + unsigned int dki_len, + const struct TALER_DenominationKeyValidityPS *dki); + + +/** + * Initialize the plugin. + * + * @param cfg configuration to use + * @return NULL on failure + */ +struct TALER_EXCHANGEDB_Plugin * +TALER_EXCHANGEDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Shutdown the plugin. + * + * @param plugin plugin to unload + */ +void +TALER_EXCHANGEDB_plugin_unload (struct TALER_EXCHANGEDB_Plugin *plugin); + + + +#endif diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h new file mode 100644 index 000000000..aecb050a7 --- /dev/null +++ b/src/include/taler_exchangedb_plugin.h @@ -0,0 +1,1431 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/taler_exchangedb_plugin.h + * @brief Low-level (statement-level) database access for the exchange + * @author Florian Dold + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGEDB_PLUGIN_H +#define TALER_EXCHANGEDB_PLUGIN_H + +#include <gnunet/gnunet_util_lib.h> +#include "taler_exchangedb_lib.h" + + +/** + * @brief Information we keep on bank transfer(s) that established a reserve. + */ +struct TALER_EXCHANGEDB_BankTransfer +{ + + /** + * Public key of the reserve that was filled. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Amount that was transferred to the exchange. + */ + struct TALER_Amount amount; + + /** + * When did the exchange receive the incoming transaction? + * (This is the execution date of the exchange's database, + * the execution date of the bank should be in @e wire). + */ + struct GNUNET_TIME_Absolute execution_date; + + /** + * Detailed wire information about the transaction. + */ + json_t *wire; + +}; + + +/** + * @brief A summary of a Reserve + */ +struct TALER_EXCHANGEDB_Reserve +{ + /** + * The reserve's public key. This uniquely identifies the reserve + */ + struct TALER_ReservePublicKeyP pub; + + /** + * The balance amount existing in the reserve + */ + struct TALER_Amount balance; + + /** + * The expiration date of this reserve + */ + struct GNUNET_TIME_Absolute expiry; +}; + + +/** + * @brief Information we keep for a withdrawn coin to reproduce + * the /withdraw operation if needed, and to have proof + * that a reserve was drained by this amount. + */ +struct TALER_EXCHANGEDB_CollectableBlindcoin +{ + + /** + * Our signature over the (blinded) coin. + */ + struct TALER_DenominationSignature sig; + + /** + * Denomination key (which coin was generated). + */ + struct TALER_DenominationPublicKey denom_pub; + + /** + * Value of the coin being exchangeed (matching the denomination key) + * plus the transaction fee. We include this in what is being + * signed so that we can verify a reserve's remaining total balance + * without needing to access the respective denomination key + * information each time. + */ + struct TALER_Amount amount_with_fee; + + /** + * Withdrawl fee charged by the exchange. This must match the Exchange's + * denomination key's withdrawl fee. If the client puts in an + * invalid withdrawl fee (too high or too low) that does not match + * the Exchange's denomination key, the withdraw operation is invalid + * and will be rejected by the exchange. The @e amount_with_fee minus + * the @e withdraw_fee is must match the value of the generated + * coin. We include this in what is being signed so that we can + * verify a exchange's accounting without needing to access the + * respective denomination key information each time. + */ + struct TALER_Amount withdraw_fee; + + /** + * Public key of the reserve that was drained. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Hash over the blinded message, needed to verify + * the @e reserve_sig. + */ + struct GNUNET_HashCode h_coin_envelope; + + /** + * Signature confirming the withdrawl, matching @e reserve_pub, + * @e denom_pub and @e h_coin_envelope. + */ + struct TALER_ReserveSignatureP reserve_sig; +}; + + + +/** + * @brief Types of operations on a reserved. + */ +enum TALER_EXCHANGEDB_ReserveOperation +{ + /** + * Money was deposited into the reserve via a bank transfer. + */ + TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE = 0, + + /** + * A Coin was withdrawn from the reserve using /withdraw. + */ + TALER_EXCHANGEDB_RO_WITHDRAW_COIN = 1 +}; + + +/** + * @brief Reserve history as a linked list. Lists all of the transactions + * associated with this reserve (such as the bank transfers that + * established the reserve and all /withdraw operations we have done + * since). + */ +struct TALER_EXCHANGEDB_ReserveHistory +{ + + /** + * Next entry in the reserve history. + */ + struct TALER_EXCHANGEDB_ReserveHistory *next; + + /** + * Type of the event, determins @e details. + */ + enum TALER_EXCHANGEDB_ReserveOperation type; + + /** + * Details of the operation, depending on @e type. + */ + union + { + + /** + * Details about a bank transfer to the exchange. + */ + struct TALER_EXCHANGEDB_BankTransfer *bank; + + /** + * Details about a /withdraw operation. + */ + struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw; + + } details; + +}; + + +/** + * @brief Specification for a /deposit operation. The combination of + * the coin's public key, the merchant's public key and the + * transaction ID must be unique. While a coin can (theoretically) be + * deposited at the same merchant twice (with partial spending), the + * merchant must either use a different public key or a different + * transaction ID for the two transactions. The same coin must not + * be used twice at the same merchant for the same transaction + * (as determined by transaction ID). (Note: we might want to + * fix #3819 and include at least h_contract as well.) + */ +struct TALER_EXCHANGEDB_Deposit +{ + /** + * Information about the coin that is being deposited. + */ + struct TALER_CoinPublicInfo coin; + + /** + * ECDSA signature affirming that the customer intends + * this coin to be deposited at the merchant identified + * by @e h_wire in relation to the contract identified + * by @e h_contract. + */ + struct TALER_CoinSpendSignatureP csig; + + /** + * Public key of the merchant. Enables later identification + * of the merchant in case of a need to rollback transactions. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash over the contract between merchant and customer + * (remains unknown to the Exchange). + */ + struct GNUNET_HashCode h_contract; + + /** + * Hash of the (canonical) representation of @e wire, used + * to check the signature on the request. Generated by + * the exchange from the detailed wire data provided by the + * merchant. + */ + struct GNUNET_HashCode h_wire; + + /** + * Detailed wire information for executing the transaction. + */ + json_t *wire; + + /** + * Merchant-generated transaction ID to detect duplicate + * transactions. + */ + uint64_t transaction_id; + + /** + * Time when this request was generated. Used, for example, to + * assess when (roughly) the income was achieved for tax purposes. + * Note that the Exchange will only check that the timestamp is not "too + * far" into the future (i.e. several days). The fact that the + * timestamp falls within the validity period of the coin's + * denomination key is irrelevant for the validity of the deposit + * request, as obviously the customer and merchant could conspire to + * set any timestamp. Also, the Exchange must accept very old deposit + * requests, as the merchant might have been unable to transmit the + * deposit request in a timely fashion (so back-dating is not + * prevented). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * How much time does the merchant have to issue a refund request? + * Zero if refunds are not allowed. After this time, the coin + * cannot be refunded. + */ + struct GNUNET_TIME_Absolute refund_deadline; + + /** + * How much time does the merchant have to execute the wire transfer? + * This time is advisory for aggregating transactions, not a hard + * constraint (as the merchant can theoretically pick any time, + * including one in the past). + */ + struct GNUNET_TIME_Absolute wire_deadline; + + /** + * Fraction of the coin's remaining value to be deposited, including + * depositing fee (if any). The coin is identified by @e coin_pub. + */ + struct TALER_Amount amount_with_fee; + + /** + * Depositing fee. + */ + struct TALER_Amount deposit_fee; + +}; + + +/** + * @brief Global information for a refreshing session. Includes + * dimensions of the operation, security parameters and + * client signatures from "/refresh/melt" and "/refresh/commit". + */ +struct TALER_EXCHANGEDB_RefreshSession +{ + + /** + * Number of coins we are melting. + */ + uint16_t num_oldcoins; + + /** + * Number of new coins we are creating. + */ + uint16_t num_newcoins; + + /** + * Index (smaller #TALER_CNC_KAPPA) which the exchange has chosen to not + * have revealed during cut and choose. + */ + uint16_t noreveal_index; + +}; + + +/** + * @brief Specification for coin in a /refresh/melt operation. + */ +struct TALER_EXCHANGEDB_RefreshMelt +{ + /** + * Information about the coin that is being melted. + */ + struct TALER_CoinPublicInfo coin; + + /** + * Signature over the melting operation. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** + * Hash of the refresh session this coin is melted into. + */ + struct GNUNET_HashCode session_hash; + + /** + * How much value is being melted? This amount includes the fees, + * so the final amount contributed to the melt is this value minus + * the fee for melting the coin. We include the fee in what is + * being signed so that we can verify a reserve's remaining total + * balance without needing to access the respective denomination key + * information each time. + */ + struct TALER_Amount amount_with_fee; + + /** + * Melting fee charged by the exchange. This must match the Exchange's + * denomination key's melting fee. If the client puts in an invalid + * melting fee (too high or too low) that does not match the Exchange's + * denomination key, the melting operation is invalid and will be + * rejected by the exchange. The @e amount_with_fee minus the @e + * melt_fee is the amount that will be credited to the melting + * session. + */ + struct TALER_Amount melt_fee; + +}; + + +/** + * @brief We have as many `struct TALER_EXCHANGEDB_RefreshCommitCoin` as there are new + * coins being created by the refresh (for each of the #TALER_CNC_KAPPA + * sets). These are the coins we ask the exchange to sign if the + * respective set is selected. + */ +struct TALER_EXCHANGEDB_RefreshCommitCoin +{ + + /** + * Encrypted data allowing those able to decrypt it to derive + * the private keys of the new coins created by the refresh. + */ + struct TALER_RefreshLinkEncrypted *refresh_link; + + /** + * Blinded message to be signed (in envelope), with @e coin_env_size bytes. + */ + char *coin_ev; + + /** + * Number of bytes in @e coin_ev. + */ + size_t coin_ev_size; + +}; + + +/** + * @brief Linked list of refresh information linked to a coin. + */ +struct TALER_EXCHANGEDB_LinkDataList +{ + /** + * Information is stored in a NULL-terminated linked list. + */ + struct TALER_EXCHANGEDB_LinkDataList *next; + + /** + * Link data, used to recover the private key of the coin + * by the owner of the old coin. + */ + struct TALER_RefreshLinkEncrypted *link_data_enc; + + /** + * Denomination public key, determines the value of the coin. + */ + struct TALER_DenominationPublicKey denom_pub; + + /** + * Signature over the blinded envelope. + */ + struct TALER_DenominationSignature ev_sig; +}; + + +/** + * @brief Enumeration to classify the different types of transactions + * that can be done with a coin. + */ +enum TALER_EXCHANGEDB_TransactionType +{ + /** + * /deposit operation. + */ + TALER_EXCHANGEDB_TT_DEPOSIT = 0, + + /** + * /refresh/melt operation. + */ + TALER_EXCHANGEDB_TT_REFRESH_MELT = 1 + +}; + + +/** + * @brief List of transactions we performed for a particular coin. + */ +struct TALER_EXCHANGEDB_TransactionList +{ + + /** + * Next pointer in the NULL-terminated linked list. + */ + struct TALER_EXCHANGEDB_TransactionList *next; + + /** + * Type of the transaction, determines what is stored in @e details. + */ + enum TALER_EXCHANGEDB_TransactionType type; + + /** + * Details about the transaction, depending on @e type. + */ + union + { + + /** + * Details if transaction was a /deposit operation. + */ + struct TALER_EXCHANGEDB_Deposit *deposit; + + /** + * Details if transaction was a /refresh/melt operation. + */ + struct TALER_EXCHANGEDB_RefreshMelt *melt; + + } details; + +}; + + +/** + * @brief All of the information from a /refresh/melt commitment. + */ +struct TALER_EXCHANGEDB_MeltCommitment +{ + + /** + * Number of coins we are melting. + */ + uint16_t num_oldcoins; + + /** + * Number of new coins we are creating. + */ + uint16_t num_newcoins; + + /** + * Array of @e num_oldcoins melt operation details. + */ + struct TALER_EXCHANGEDB_RefreshMelt *melts; + + /** + * Array of @e num_newcoins denomination keys + */ + struct TALER_DenominationPublicKey *denom_pubs; + + /** + * 2D-Array of #TALER_CNC_KAPPA and @e num_newcoins commitments. + */ + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins[TALER_CNC_KAPPA]; + + /** + * 2D-Array of #TALER_CNC_KAPPA and @e new_oldcoins links. + */ + struct TALER_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA]; +}; + + +/** + * @brief Handle for a database session (per-thread, for transactions). + */ +struct TALER_EXCHANGEDB_Session; + + +/** + * Function called with details about deposits that + * have been made, with the goal of executing the + * corresponding wire transaction. + * + * @param cls closure + * @param rowid unique ID for the deposit in our DB, used for marking + * it as 'tiny' or 'done' + * @param merchant_pub public key of the merchant + * @param coin_pub public key of the coin + * @param amount_with_fee amount that was deposited including fee + * @param deposit_fee amount the exchange gets to keep as transaction fees + * @param transaction_id unique transaction ID chosen by the merchant + * @param h_contract hash of the contract between merchant and customer + * @param wire_deadline by which the merchant adviced that he would like the + * wire transfer to be executed + * @param wire wire details for the merchant, NULL from iterate_matching_deposits() + * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop + */ +typedef int +(*TALER_EXCHANGEDB_DepositIterator)(void *cls, + unsigned long long rowid, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + uint64_t transaction_id, + const struct GNUNET_HashCode *h_contract, + struct GNUNET_TIME_Absolute wire_deadline, + const json_t *wire); + + +/** + * Function called with the session hashes and transfer secret + * information for a given coin. + * + * @param cls closure + * @param session_hash a session the coin was melted in + * @param transfer_pub public transfer key for the session + * @param shared_secret_enc set to shared secret for the session + */ +typedef void +(*TALER_EXCHANGEDB_TransferDataCallback)(void *cls, + const struct GNUNET_HashCode *session_hash, + const struct TALER_TransferPublicKeyP *transfer_pub, + const struct TALER_EncryptedLinkSecretP *shared_secret_enc); + + +/** + * Function called with the results of the lookup of the + * wire transfer identifier information. Only called if + * we are at least aware of the transaction existing. + * + * @param cls closure + * @param wtid wire transfer identifier, NULL + * if the transaction was not yet done + * @param coin_contribution how much did the coin we asked about + * contribute to the total transfer value? (deposit value including fee) + * @param coin_fee how much did the exchange charge for the deposit fee + * @param execution_time when was the transaction done, or + * when we expect it to be done (if @a wtid was NULL) + */ +typedef void +(*TALER_EXCHANGEDB_DepositWtidCallback)(void *cls, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_Amount *coin_contribution, + const struct TALER_Amount *coin_fee, + struct GNUNET_TIME_Absolute execution_time); + + +/** + * Function called with the results of the lookup of the + * transaction data associated with a wire transfer identifier. + * + * @param cls closure + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param coin_pub which public key was this payment about + * @param coin_value amount contributed by this coin in total (with fee) + * @param coin_fee applicable fee for this coin + */ +typedef void +(*TALER_EXCHANGEDB_WireTransferDataCallback)(void *cls, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_value, + const struct TALER_Amount *coin_fee); + + +/** + * Callback with data about a prepared transaction. + * + * @param cls closure + * @param rowid row identifier used to mark prepared transaction as done + * @param buf transaction data that was persisted, NULL on error + * @param buf_size number of bytes in @a buf, 0 on error + */ +typedef void +(*TALER_EXCHANGEDB_WirePreparationCallback) (void *cls, + unsigned long long rowid, + const char *buf, + size_t buf_size); + + +/** + * @brief The plugin API, returned from the plugin's "init" function. + * The argument given to "init" is simply a configuration handle. + */ +struct TALER_EXCHANGEDB_Plugin +{ + + /** + * Closure for all callbacks. + */ + void *cls; + + /** + * Name of the library which generated this plugin. Set by the + * plugin loader. + */ + char *library_name; + + /** + * Get the thread-local database-handle. + * Connect to the db if the connection does not exist yet. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the + * database default one + * @param the database connection, or NULL on error + */ + struct TALER_EXCHANGEDB_Session * + (*get_session) (void *cls, + int temporary); + + + /** + * Drop the temporary taler schema. This is only useful for testcases. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + int + (*drop_temporary) (void *cls, + struct TALER_EXCHANGEDB_Session *db); + + + /** + * Create the necessary tables if they are not present + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param temporary should we use a temporary schema + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + int + (*create_tables) (void *cls, + int temporary); + + + /** + * Start a transaction. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @return #GNUNET_OK on success + */ + int + (*start) (void *cls, + struct TALER_EXCHANGEDB_Session *session); + + + /** + * Commit a transaction. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @return #GNUNET_OK on success, #GNUNET_NO if the transaction + * can be retried, #GNUNET_SYSERR on hard failures + */ + int + (*commit) (void *cls, + struct TALER_EXCHANGEDB_Session *session); + + + /** + * Abort/rollback a transaction. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + */ + void + (*rollback) (void *cls, + struct TALER_EXCHANGEDB_Session *session); + + + /** + * Insert information about a denomination key and in particular + * the properties (value, fees, expiration times) the coins signed + * with this key have. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param denom_pub the public key used for signing coins of this denomination + * @param issue issuing information with value, fees and other info about the coin + * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure + */ + int + (*insert_denomination_info) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue); + + + /** + * Fetch information about a denomination key. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param denom_pub the public key used for signing coins of this denomination + * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL + * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure + */ + int + (*get_denomination_info) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_DenominationPublicKey *denom_pub, + struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue); + + + /** + * Get the summary of a reserve. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param db the database connection handle + * @param[in,out] reserve the reserve data. The public key of the reserve should be set + * in this structure; it is used to query the database. The balance + * and expiration are then filled accordingly. + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + int + (*reserve_get) (void *cls, + struct TALER_EXCHANGEDB_Session *db, + struct TALER_EXCHANGEDB_Reserve *reserve); + + + /** + * Insert a incoming transaction into reserves. New reserves are + * also created through this function. Note that this API call + * starts (and stops) its own transaction scope (so the application + * must not do so). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param db the database connection handle + * @param reserve_pub public key of the reserve + * @param balance the amount that has to be added to the reserve + * @param execution_time when was the amount added + * @param details bank transaction details justifying the increment, + * must be unique for each incoming transaction + * @return #GNUNET_OK upon success; #GNUNET_NO if the given + * @a details are already known for this @a reserve_pub, + * #GNUNET_SYSERR upon failures (DB error, incompatible currency) + */ + int + (*reserves_in_insert) (void *cls, + struct TALER_EXCHANGEDB_Session *db, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *balance, + struct GNUNET_TIME_Absolute execution_time, + const json_t *details); + + + /** + * Locate the response for a /withdraw request under the + * key of the hash of the blinded message. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param h_blind hash of the blinded coin to be signed (will match + * `h_coin_envelope` in the @a collectable to be returned) + * @param collectable corresponding collectable coin (blind signature) + * if a coin is found + * @return #GNUNET_SYSERR on internal error + * #GNUNET_NO if the collectable was not found + * #GNUNET_YES on success + */ + int + (*get_withdraw_info) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_blind, + struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable); + + + /** + * Store collectable bit coin under the corresponding + * hash of the blinded message. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param collectable corresponding collectable coin (blind signature) + * if a coin is found + * @return #GNUNET_SYSERR on internal error + * #GNUNET_NO if the collectable was not found + * #GNUNET_YES on success + */ + int + (*insert_withdraw_info) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable); + + + /** + * Get all of the transaction history associated with the specified + * reserve. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to use + * @param reserve_pub public key of the reserve + * @return known transaction history (NULL if reserve is unknown) + */ + struct TALER_EXCHANGEDB_ReserveHistory * + (*get_reserve_history) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_ReservePublicKeyP *reserve_pub); + + + /** + * Free memory associated with the given reserve history. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param rh history to free. + */ + void + (*free_reserve_history) (void *cls, + struct TALER_EXCHANGEDB_ReserveHistory *rh); + + + /** + * Check if we have the specified deposit already in the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param deposit deposit to search for + * @return #GNUNET_YES if we know this operation, + * #GNUNET_NO if this exact deposit is unknown to us, + * #GNUNET_SYSERR on DB error + */ + int + (*have_deposit) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_Deposit *deposit); + + + /** + * Insert information about deposited coin into the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit deposit information to store + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ + int + (*insert_deposit) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_EXCHANGEDB_Deposit *deposit); + + + /** + * Mark a deposit as tiny, thereby declaring that it cannot be + * executed by itself and should no longer be returned by + * @e iterate_ready_deposits() + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_rowid identifies the deposit row to modify + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ + int + (*mark_deposit_tiny) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid); + + + /** + * Mark a deposit as done, thereby declaring that it cannot be + * executed at all anymore, and should no longer be returned by + * @e iterate_ready_deposits() or @e iterate_matching_deposits(). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_rowid identifies the deposit row to modify + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ + int + (*mark_deposit_done) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid); + + + /** + * Obtain information about deposits that are ready to be executed. + * Such deposits must not be marked as "tiny" or "done", and the + * execution time must be in the past. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param deposit_cb function to call for ONE such deposit + * @param deposit_cb_cls closure for @a deposit_cb + * @return number of rows processed, 0 if none exist, + * #GNUNET_SYSERR on error + */ + int + (*get_ready_deposit) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + TALER_EXCHANGEDB_DepositIterator deposit_cb, + void *deposit_cb_cls); + + + /** + * Obtain information about other pending deposits for the same + * destination. Those deposits must not already be "done". + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session connection to the database + * @param h_wire destination of the wire transfer + * @param merchant_pub public key of the merchant + * @param deposit_cb function to call for each deposit + * @param deposit_cb_cls closure for @a deposit_cb + * @param limit maximum number of matching deposits to return + * @return number of rows processed, 0 if none exist, + * #GNUNET_SYSERR on error + */ + int + (*iterate_matching_deposits) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_wire, + const struct TALER_MerchantPublicKeyP *merchant_pub, + TALER_EXCHANGEDB_DepositIterator deposit_cb, + void *deposit_cb_cls, + uint32_t limit); + + + /** + * Lookup refresh session data under the given @a session_hash. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database handle to use + * @param session_hash hash over the melt to use for the lookup + * @param[out] refresh_session where to store the result + * @return #GNUNET_YES on success, + * #GNUNET_NO if not found, + * #GNUNET_SYSERR on DB failure + */ + int + (*get_refresh_session) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + struct TALER_EXCHANGEDB_RefreshSession *refresh_session); + + + /** + * Store new refresh session data under the given @a session_hash. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database handle to use + * @param session_hash hash over the melt to use to locate the session + * @param refresh_session session data to store + * @return #GNUNET_YES on success, + * #GNUNET_SYSERR on DB failure + */ + int + (*create_refresh_session) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + const struct TALER_EXCHANGEDB_RefreshSession *refresh_session); + + + /** + * Store the given /refresh/melt request in the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param oldcoin_index index of the coin to store + * @param melt coin melt operation details to store; includes + * the session hash of the melt + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ + int + (*insert_refresh_melt) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + uint16_t oldcoin_index, + const struct TALER_EXCHANGEDB_RefreshMelt *melt); + + + /** + * Get information about melted coin details from the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param oldcoin_index index of the coin to retrieve + * @param melt melt data to fill in, can be NULL + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ + int + (*get_refresh_melt) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t oldcoin_index, + struct TALER_EXCHANGEDB_RefreshMelt *melt); + + + /** + * Store in the database which coin(s) we want to create + * in a given refresh operation. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param num_newcoins number of coins to generate, size of the @a denom_pubs array + * @param denom_pubs array denominations of the coins to create + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ + int + (*insert_refresh_order) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t num_newcoins, + const struct TALER_DenominationPublicKey *denom_pubs); + + + /** + * Lookup in the database for the @a num_newcoins coins that we want to + * create in the given refresh operation. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param num_newcoins size of the @a denom_pubs array + * @param[out] denom_pubs where to write @a num_newcoins denomination keys + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ + int + (*get_refresh_order) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t num_newcoins, + struct TALER_DenominationPublicKey *denom_pubs); + + + /** + * Store information about the commitments of the given index @a i + * for the given refresh session in the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA + * @param num_newcoins coin index size of the @a commit_coins array + * @param commit_coin array of coin commitments to store + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on error + */ + int + (*insert_refresh_commit_coins) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_newcoins, + const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins); + + + /** + * Obtain information about the commitment of the + * given coin of the given refresh session from the database. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose set index (1st dimension) + * @param num_coins size of the @a commit_coins array + * @param[out] commit_coins array of coin commitments to return + * @return #GNUNET_OK on success + * #GNUNET_NO if not found + * #GNUNET_SYSERR on error + */ + int + (*get_refresh_commit_coins) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_coins, + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins); + + + /** + * Store the commitment to the given (encrypted) refresh link data + * for the given refresh session. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA + * @param num_links size of the @a commit_link array + * @param commit_links array of link information to store + * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success + */ + int + (*insert_refresh_commit_links) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_links, + const struct TALER_RefreshCommitLinkP *commit_links); + + /** + * Obtain the commited (encrypted) refresh link data + * for the given refresh session. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @param cnc_index cut and choose index (1st dimension) + * @param num_links size of the @a links array to return + * @param[out] links array link information to return + * @return #GNUNET_SYSERR on internal error, + * #GNUNET_NO if commitment was not found + * #GNUNET_OK on success + */ + int + (*get_refresh_commit_links) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t cnc_index, + uint16_t num_links, + struct TALER_RefreshCommitLinkP *links); + + + /** + * Get all of the information from the given melt commit operation. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection to use + * @param session_hash hash to identify refresh session + * @return NULL if the @a session_hash does not correspond to any known melt + * operation + */ + struct TALER_EXCHANGEDB_MeltCommitment * + (*get_melt_commitment) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash); + + + /** + * Free information about a melt commitment. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param mc melt commitment data to free + */ + void + (*free_melt_commitment) (void *cls, + struct TALER_EXCHANGEDB_MeltCommitment *mc); + + + /** + * Insert signature of a new coin generated during refresh into + * the database indexed by the refresh session and the index + * of the coin. This data is later used should an old coin + * be used to try to obtain the private keys during "/refresh/link". + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param session_hash hash to identify refresh session + * @param newcoin_index coin index + * @param ev_sig coin signature + * @return #GNUNET_OK on success + */ + int + (*insert_refresh_out) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + uint16_t newcoin_index, + const struct TALER_DenominationSignature *ev_sig); + + + /** + * Obtain the link data of a coin, that is the encrypted link + * information, the denomination keys and the signatures. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param session_hash session to get linkage data for + * @return all known link data for the session + */ + struct TALER_EXCHANGEDB_LinkDataList * + (*get_link_data_list) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash); + + + /** + * Free memory of the link data list. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param ldl link data list to release + */ + void + (*free_link_data_list) (void *cls, + struct TALER_EXCHANGEDB_LinkDataList *ldl); + + + /** + * Obtain shared secret and transfer public key from the public key of + * the coin. This information and the link information returned by + * @e get_link_data_list() enable the owner of an old coin to determine + * the private keys of the new coins after the melt. + * + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param coin_pub public key of the coin + * @param tdc function to call for each session the coin was melted into + * @param tdc_cls closure for @a tdc + * @return #GNUNET_OK on success, + * #GNUNET_NO on failure (not found) + * #GNUNET_SYSERR on internal failure (database issue) + */ + int + (*get_transfer) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + TALER_EXCHANGEDB_TransferDataCallback tdc, + void *tdc_cls); + + + /** + * Compile a list of all (historic) transactions performed + * with the given coin (/refresh/melt and /deposit operations). + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param coin_pub coin to investigate + * @return list of transactions, NULL if coin is fresh + */ + struct TALER_EXCHANGEDB_TransactionList * + (*get_coin_transactions) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub); + + + /** + * Free linked list of transactions. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param list list to free + */ + void + (*free_coin_transaction_list) (void *cls, + struct TALER_EXCHANGEDB_TransactionList *list); + + + /** + * Lookup the list of Taler transactions that was aggregated + * into a wire transfer by the respective @a raw_wtid. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param session database connection + * @param wtid the raw wire transfer identifier we used + * @param cb function to call on each transaction found + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors, + * #GNUNET_NO if we found no results + */ + int + (*lookup_wire_transfer) (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_WireTransferIdentifierRawP *wtid, + TALER_EXCHANGEDB_WireTransferDataCallback cb, + void *cb_cls); + + + /** + * Try to find the wire transfer details for a deposit operation. + * If we did not execute the deposit yet, return when it is supposed + * to be executed. + * + * @param cls closure + * @param session database connection + * @param h_contract hash of the contract + * @param h_wire hash of merchant wire details + * @param coin_pub public key of deposited coin + * @param merchant_pub merchant public key + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure to pass to @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors, + * #GNUNET_NO if nothing was found + */ + int + (*wire_lookup_deposit_wtid)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id, + TALER_EXCHANGEDB_DepositWtidCallback cb, + void *cb_cls); + + + /** + * Function called to insert aggregation information into the DB. + * + * @param cls closure + * @param session database connection + * @param wtid the raw wire transfer identifier we used + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param h_contract which contract was this payment about + * @param transaction_id merchant's transaction ID for the payment + * @param execution_time when did we execute the transaction + * @param coin_pub which public key was this payment about + * @param coin_value amount contributed by this coin in total + * @param coin_fee deposit fee charged by exchange for this coin + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ + int + (*insert_aggregation_tracking)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_HashCode *h_wire, + const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *coin_value, + const struct TALER_Amount *coin_fee); + + + /** + * Function called to insert wire transfer commit data into the DB. + * + * @param cls closure + * @param session database connection + * @param type type of the wire transfer (i.e. "sepa") + * @param buf buffer with wire transfer preparation data + * @param buf_size number of bytes in @a buf + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ + int + (*wire_prepare_data_insert)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + const char *type, + const char *buf, + size_t buf_size); + + + /** + * Function called to mark wire transfer commit data as finished. + * + * @param cls closure + * @param session database connection + * @param rowid which entry to mark as finished + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ + int + (*wire_prepare_data_mark_finished)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + unsigned long long rowid); + + + /** + * Function called to get an unfinished wire transfer + * preparation data. Fetches at most one item. + * + * @param cls closure + * @param session database connection + * @param type type fo the wire transfer (i.e. "sepa") + * @param cb function to call for ONE unfinished item + * @param cb_cls closure for @a cb + * @return #GNUNET_OK on success, + * #GNUNET_NO if there are no entries, + * #GNUNET_SYSERR on DB errors + */ + int + (*wire_prepare_data_get)(void *cls, + struct TALER_EXCHANGEDB_Session *session, + const char *type, + TALER_EXCHANGEDB_WirePreparationCallback cb, + void *cb_cls); + + +}; + + +#endif /* _TALER_EXCHANGE_DB_H */ diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h deleted file mode 100644 index 1502edfbc..000000000 --- a/src/include/taler_mint_service.h +++ /dev/null @@ -1,1220 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file include/taler_mint_service.h - * @brief C interface of libtalermint, a C library to use mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#ifndef _TALER_MINT_SERVICE_H -#define _TALER_MINT_SERVICE_H - -#include "taler_util.h" - -/* ********************* event loop *********************** */ - -/** - * @brief Handle to this library context. This is where the - * main event loop logic lives. - */ -struct TALER_MINT_Context; - - -/** - * Initialise a context. A context should be used for each thread and should - * not be shared among multiple threads. - * - * @return the context, NULL on error (failure to initialize) - */ -struct TALER_MINT_Context * -TALER_MINT_init (void); - - -/** - * Obtain the information for a select() call to wait until - * #TALER_MINT_perform() is ready again. Note that calling - * any other TALER_MINT-API may also imply that the library - * is again ready for #TALER_MINT_perform(). - * - * Basically, a client should use this API to prepare for select(), - * then block on select(), then call #TALER_MINT_perform() and then - * start again until the work with the context is done. - * - * This function will NOT zero out the sets and assumes that @a max_fd - * and @a timeout are already set to minimal applicable values. It is - * safe to give this API FD-sets and @a max_fd and @a timeout that are - * already initialized to some other descriptors that need to go into - * the select() call. - * - * @param ctx context to get the event loop information for - * @param read_fd_set will be set for any pending read operations - * @param write_fd_set will be set for any pending write operations - * @param except_fd_set is here because curl_multi_fdset() has this argument - * @param max_fd set to the highest FD included in any set; - * if the existing sets have no FDs in it, the initial - * value should be "-1". (Note that `max_fd + 1` will need - * to be passed to select().) - * @param timeout set to the timeout in milliseconds (!); -1 means - * no timeout (NULL, blocking forever is OK), 0 means to - * proceed immediately with #TALER_MINT_perform(). - */ -void -TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *except_fd_set, - int *max_fd, - long *timeout); - - -/** - * Run the main event loop for the Taler interaction. - * - * @param ctx the library context - */ -void -TALER_MINT_perform (struct TALER_MINT_Context *ctx); - - -/** - * Cleanup library initialisation resources. This function should be called - * after using this library to cleanup the resources occupied during library's - * initialisation. - * - * @param ctx the library context - */ -void -TALER_MINT_fini (struct TALER_MINT_Context *ctx); - - -/* ********************* /keys *********************** */ - - -/** - * List of possible options to be passed to - * #TALER_MINT_connect(). - */ -enum TALER_MINT_Option -{ - /** - * Terminator (end of option list). - */ - TALER_MINT_OPTION_END = 0 - -}; - - -/** - * @brief Mint's signature key - */ -struct TALER_MINT_SigningPublicKey -{ - /** - * The signing public key - */ - struct TALER_MintPublicKeyP key; - - /** - * Validity start time - */ - struct GNUNET_TIME_Absolute valid_from; - - /** - * Validity expiration time - */ - struct GNUNET_TIME_Absolute valid_until; -}; - - -/** - * @brief Public information about a mint's denomination key - */ -struct TALER_MINT_DenomPublicKey -{ - /** - * The public key - */ - struct TALER_DenominationPublicKey key; - - /** - * The hash of the public key. - */ - struct GNUNET_HashCode h_key; - - /** - * Timestamp indicating when the denomination key becomes valid - */ - struct GNUNET_TIME_Absolute valid_from; - - /** - * Timestamp indicating when the denomination key can’t be used anymore to - * withdraw new coins. - */ - struct GNUNET_TIME_Absolute withdraw_valid_until; - - /** - * Timestamp indicating when coins of this denomination become invalid. - */ - struct GNUNET_TIME_Absolute deposit_valid_until; - - /** - * When do signatures with this denomination key become invalid? - * After this point, these signatures cannot be used in (legal) - * disputes anymore, as the Mint is then allowed to destroy its side - * of the evidence. @e expire_legal is expected to be significantly - * larger than @e expire_spend (by a year or more). - */ - struct GNUNET_TIME_Absolute expire_legal; - - /** - * The value of this denomination - */ - struct TALER_Amount value; - - /** - * The applicable fee for withdrawing a coin of this denomination - */ - struct TALER_Amount fee_withdraw; - - /** - * The applicable fee to spend a coin of this denomination - */ - struct TALER_Amount fee_deposit; - - /** - *The applicable fee to melt/refresh a coin of this denomination - */ - struct TALER_Amount fee_refresh; -}; - - -/** - * @brief Information we get from the mint about auditors. - */ -struct TALER_MINT_AuditorInformation -{ - /** - * Public key of the auditing institution. - */ - struct TALER_AuditorPublicKeyP auditor_pub; - - /** - * URL of the auditing institution. The application must check that - * this is an acceptable auditor for its purpose and also verify - * that the @a auditor_pub matches the auditor's public key given at - * that website. We expect that in practice software is going to - * often ship with an initial list of accepted auditors, just like - * browsers ship with a CA root store. - * - * This field may be NULL. (#3987). - */ - const char *auditor_url; - - /** - * Number of denomination keys audited by this auditor. - */ - unsigned int num_denom_keys; - - /** - * Array of length @a denom_keys with the denomination - * keys audited by this auditor. Note that the array - * elements point to the same locations as the entries - * in the key's main `denom_keys` array. - */ - const struct TALER_MINT_DenomPublicKey **denom_keys; -}; - - -/** - * @brief Information about keys from the mint. - */ -struct TALER_MINT_Keys -{ - - /** - * Long-term offline signing key of the mint. - */ - struct TALER_MasterPublicKeyP master_pub; - - /** - * Array of the mint's online signing keys. - */ - struct TALER_MINT_SigningPublicKey *sign_keys; - - /** - * Array of the mint's denomination keys. - */ - struct TALER_MINT_DenomPublicKey *denom_keys; - - /** - * Array of the keys of the auditors of the mint. - */ - struct TALER_MINT_AuditorInformation *auditors; - - /** - * Length of the @e sign_keys array. - */ - unsigned int num_sign_keys; - - /** - * Length of the @e denom_keys array. - */ - unsigned int num_denom_keys; - - /** - * Length of the @e auditors array. - */ - unsigned int num_auditors; - -}; - - -/** - * Function called with information about who is auditing - * a particular mint and what key the mint is using. - * - * @param cls closure - * @param keys information about the various keys used - * by the mint - */ -typedef void -(*TALER_MINT_CertificationCallback) (void *cls, - const struct TALER_MINT_Keys *keys); - - -/** - * @brief Handle to the mint. This is where we interact with - * a particular mint and keep the per-mint information. - */ -struct TALER_MINT_Handle; - - -/** - * Initialise a connection to the mint. Will connect to the - * mint and obtain information about the mint's master public - * key and the mint's auditor. The respective information will - * be passed to the @a cert_cb once available, and all future - * interactions with the mint will be checked to be signed - * (where appropriate) by the respective master key. - * - * @param ctx the context - * @param url HTTP base URL for the mint - * @param cert_cb function to call with the mint's certification information - * @param cert_cb_cls closure for @a cert_cb - * @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END. - * @return the mint handle; NULL upon error - */ -struct TALER_MINT_Handle * -TALER_MINT_connect (struct TALER_MINT_Context *ctx, - const char *url, - TALER_MINT_CertificationCallback cert_cb, - void *cert_cb_cls, - ...); - - -/** - * Disconnect from the mint. - * - * @param mint the mint handle - */ -void -TALER_MINT_disconnect (struct TALER_MINT_Handle *mint); - - -/** - * Obtain the keys from the mint. - * - * @param mint the mint handle - * @return the mint's key set - */ -const struct TALER_MINT_Keys * -TALER_MINT_get_keys (const struct TALER_MINT_Handle *mint); - - -/** - * Test if the given @a pub is a the current signing key from the mint - * according to @a keys. - * - * @param keys the mint's key set - * @param pub claimed current online signing key for the mint - * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key - */ -int -TALER_MINT_test_signing_key (const struct TALER_MINT_Keys *keys, - const struct TALER_MintPublicKeyP *pub); - - -/** - * Obtain the denomination key details from the mint. - * - * @param keys the mint's key set - * @param pk public key of the denomination to lookup - * @return details about the given denomination key, NULL if the key is not - * found - */ -const struct TALER_MINT_DenomPublicKey * -TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys, - const struct TALER_DenominationPublicKey *pk); - - -/** - * Obtain the denomination key details from the mint. - * - * @param keys the mint's key set - * @param hc hash of the public key of the denomination to lookup - * @return details about the given denomination key - */ -const struct TALER_MINT_DenomPublicKey * -TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys, - const struct GNUNET_HashCode *hc); - - -/* ********************* /wire *********************** */ - - -/** - * @brief A Wire format inquiry handle - */ -struct TALER_MINT_WireHandle; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * wire format inquiry request to a mint. - * - * The callback is invoked multiple times, once for each supported @a - * method. Finally, it is invoked one more time with cls/0/NULL/NULL - * to indicate the end of the iteration. If any request fails to - * generate a valid response from the mint, @a http_status will also - * be zero and the iteration will also end. Thus, the iteration - * always ends with a final call with an @a http_status of 0. If the - * @a http_status is already 0 on the first call, then the response to - * the /wire request was invalid. Later, clients can tell the - * difference between @a http_status of 0 indicating a failed - * /wire/method request and a regular end of the iteration by @a - * method being non-NULL. If the mint simply correctly asserts that - * it does not support any methods, @a method will be NULL but the @a - * http_status will be #MHD_HTTP_OK for the first call (followed by a - * cls/0/NULL/NULL call to signal the end of the iteration). - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param method wire format method supported, i.e. "test" or "sepa", or NULL - * if already the /wire request failed. - * @param obj the received JSON reply, if successful this should be the wire - * format details as provided by /wire/METHOD/, or NULL if the - * reply was not in JSON format (in this case, the client might - * want to do an HTTP request to /wire/METHOD/ with a browser to - * provide more information to the user about the @a method). - */ -typedef void -(*TALER_MINT_WireResultCallback) (void *cls, - unsigned int http_status, - const char *method, - json_t *obj); - - -/** - * Obtain information about a mint's wire instructions. - * A mint may provide wire instructions for creating - * a reserve. The wire instructions also indicate - * which wire formats merchants may use with the mint. - * This API is typically used by a wallet for wiring - * funds, and possibly by a merchant to determine - * supported wire formats. - * - * Note that while we return the (main) response verbatim to the - * caller for further processing, we do already verify that the - * response is well-formed (i.e. that signatures included in the - * response are all valid). If the mint's reply is not well-formed, - * we return an HTTP status code of zero to @a cb. - * - * @param mint the mint handle; the mint must be ready to operate - * @param wire_cb the callback to call when a reply for this request is available - * @param wire_cb_cls closure for the above callback - * @return a handle for this request - */ -struct TALER_MINT_WireHandle * -TALER_MINT_wire (struct TALER_MINT_Handle *mint, - TALER_MINT_WireResultCallback wire_cb, - void *wire_cb_cls); - - -/** - * Cancel a wire information request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param wh the wire information request handle - */ -void -TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wh); - - -/* ********************* /deposit *********************** */ - - -/** - * @brief A Deposit Handle - */ -struct TALER_MINT_DepositHandle; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * deposit permission request to a mint. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param obj the received JSON reply, should be kept as proof (and, in case of errors, - * be forwarded to the customer) - */ -typedef void -(*TALER_MINT_DepositResultCallback) (void *cls, - unsigned int http_status, - json_t *obj); - - -/** - * Submit a deposit permission to the mint and get the mint's - * response. This API is typically used by a merchant. Note that - * while we return the response verbatim to the caller for further - * processing, we do already verify that the response is well-formed - * (i.e. that signatures included in the response are all valid). If - * the mint's reply is not well-formed, we return an HTTP status code - * of zero to @a cb. - * - * We also verify that the @a coin_sig is valid for this deposit - * request, and that the @a ub_sig is a valid signature for @a - * coin_pub. Also, the @a mint must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the transaction with the mint and instead return NULL. - * - * @param mint the mint handle; the mint must be ready to operate - * @param amount the amount to be deposited - * @param wire_deadline execution date, until which the merchant would like the mint to settle the balance (advisory, the mint cannot be - * forced to settle in the past or upon very short notice, but of course a well-behaved mint will limit aggregation based on the advice received) - * @param wire_details the merchant’s account details, in a format supported by the mint - * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) - * @param coin_pub coin’s public key - * @param denom_pub denomination key with which the coin is signed - * @param denom_sig mint’s unblinded signature of the coin - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed) - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_MINT_DepositHandle * -TALER_MINT_deposit (struct TALER_MINT_Handle *mint, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute wire_deadline, - json_t *wire_details, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationSignature *denom_sig, - const struct TALER_DenominationPublicKey *denom_pub, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_CoinSpendSignatureP *coin_sig, - TALER_MINT_DepositResultCallback cb, - void *cb_cls); - - -/** - * Cancel a deposit permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit the deposit permission request handle - */ -void -TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit); - - -/* ********************* /reserve/status *********************** */ - - -/** - * @brief A /reserve/status Handle - */ -struct TALER_MINT_ReserveStatusHandle; - - -/** - * Ways how a reserve's balance may change. - */ -enum TALER_MINT_ReserveTransactionType { - - /** - * Deposit into the reserve. - */ - TALER_MINT_RTT_DEPOSIT, - - /** - * Withdrawal from the reserve. - */ - TALER_MINT_RTT_WITHDRAWAL - -}; - - -/** - * @brief Entry in the reserve's transaction history. - */ -struct TALER_MINT_ReserveHistory -{ - - /** - * Type of the transaction. - */ - enum TALER_MINT_ReserveTransactionType type; - - /** - * Amount transferred (in or out). - */ - struct TALER_Amount amount; - - /** - * Details depending on @e type. - */ - union { - - /** - * Transaction details for the incoming transaction. - */ - json_t *wire_in_details; - - /** - * Signature authorizing the withdrawal for outgoing transaction. - */ - json_t *out_authorization_sig; - - } details; - -}; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * deposit permission request to a mint. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param[in] json original response in JSON format (useful only for diagnostics) - * @param balance current balance in the reserve, NULL on error - * @param history_length number of entries in the transaction history, 0 on error - * @param history detailed transaction history, NULL on error - */ -typedef void -(*TALER_MINT_ReserveStatusResultCallback) (void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_Amount *balance, - unsigned int history_length, - const struct TALER_MINT_ReserveHistory *history); - - -/** - * Submit a request to obtain the transaction history of a reserve - * from the mint. Note that while we return the full response to the - * caller for further processing, we do already verify that the - * response is well-formed (i.e. that signatures included in the - * response are all valid and add up to the balance). If the mint's - * reply is not well-formed, we return an HTTP status code of zero to - * @a cb. - * - * @param mint the mint handle; the mint must be ready to operate - * @param reserve_pub public key of the reserve to inspect - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_MINT_ReserveStatusHandle * -TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint, - const struct TALER_ReservePublicKeyP *reserve_pub, - TALER_MINT_ReserveStatusResultCallback cb, - void *cb_cls); - - -/** - * Cancel a withdraw status request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param wsh the withdraw status request handle - */ -void -TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh); - - -/* ********************* /reserve/withdraw *********************** */ - - -/** - * @brief A /reserve/withdraw Handle - */ -struct TALER_MINT_ReserveWithdrawHandle; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * deposit permission request to a mint. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param sig signature over the coin, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -typedef void -(*TALER_MINT_ReserveWithdrawResultCallback) (void *cls, - unsigned int http_status, - const struct TALER_DenominationSignature *sig, - json_t *full_response); - - -/** - * Withdraw a coin from the mint using a /reserve/withdraw request. This - * API is typically used by a wallet. Note that to ensure that no - * money is lost in case of hardware failures, the caller must have - * committed (most of) the arguments to disk before calling, and be - * ready to repeat the request with the same arguments in case of - * failures. - * - * @param mint the mint handle; the mint must be ready to operate - * @param pk kind of coin to create - * @param reserve_priv private key of the reserve to withdraw from - * @param coin_priv where to store the coin's private key, - * caller must have committed this value to disk before the call (with @a pk) - * @param blinding_key where to store the coin's blinding key - * caller must have committed this value to disk before the call (with @a pk) - * @param res_cb the callback to call when the final result for this request is available - * @param res_cb_cls closure for @a res_cb - * @return NULL - * if the inputs are invalid (i.e. denomination key not with this mint). - * In this case, the callback is not called. - */ -struct TALER_MINT_ReserveWithdrawHandle * -TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint, - const struct TALER_MINT_DenomPublicKey *pk, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - const struct TALER_DenominationBlindingKey *blinding_key, - TALER_MINT_ReserveWithdrawResultCallback res_cb, - void *res_cb_cls); - - -/** - * Cancel a withdraw status request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param sign the withdraw sign request handle - */ -void -TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign); - - -/* ********************* /refresh/melt+reveal ***************************** */ - - -/** - * Melt (partially spent) coins to obtain fresh coins that are - * unlinkable to the original coin(s). Note that melting more - * than one coin in a single request will make those coins linkable, - * so the safest operation only melts one coin at a time. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, is operation does - * not actually initiate the request. Instead, it generates a buffer - * which the caller must store before proceeding with the actual call - * to #TALER_MINT_refresh_melt() that will generate the request. - * - * This function does verify that the given request data is internally - * consistent. However, the @a melts_sigs are only verified if @a - * check_sigs is set to #GNUNET_YES, as this may be relatively - * expensive and should be redundant. - * - * Aside from some non-trivial cryptographic operations that might - * take a bit of CPU time to complete, this function returns - * its result immediately and does not start any asynchronous - * processing. This function is also thread-safe. - * - * @param num_melts number of coins that are being melted (typically 1) - * @param melt_privs array of @a num_melts private keys of the coins to melt - * @param melt_amounts array of @a num_melts amounts specifying how much - * each coin will contribute to the melt (including fee) - * @param melt_sigs array of @a num_melts signatures affirming the - * validity of the public keys corresponding to the - * @a melt_privs private keys - * @param melt_pks array of @a num_melts denomination key information - * records corresponding to the @a melt_sigs - * validity of the keys - * @param check_sigs verify the validity of the signatures of @a melt_sigs - * @param fresh_pks_len length of the @a pks array - * @param fresh_pks array of @a pks_len denominations of fresh coins to create - * @param[out] res_size set to the size of the return value, or 0 on error - * @return NULL - * if the inputs are invalid (i.e. denomination key not with this mint). - * Otherwise, pointer to a buffer of @a res_size to store persistently - * before proceeding to #TALER_MINT_refresh_melt(). - * Non-null results should be freed using #GNUNET_free(). - */ -char * -TALER_MINT_refresh_prepare (unsigned int num_melts, - const struct TALER_CoinSpendPrivateKeyP *melt_privs, - const struct TALER_Amount *melt_amounts, - const struct TALER_DenominationSignature *melt_sigs, - const struct TALER_MINT_DenomPublicKey *melt_pks, - int check_sigs, - unsigned int fresh_pks_len, - const struct TALER_MINT_DenomPublicKey *fresh_pks, - size_t *res_size); - - -/* ********************* /refresh/melt ***************************** */ - -/** - * @brief A /refresh/melt Handle - */ -struct TALER_MINT_RefreshMeltHandle; - - -/** - * Callbacks of this type are used to notify the application about the - * result of the /refresh/melt stage. If successful, the @a noreveal_index - * should be committed to disk prior to proceeding #TALER_MINT_refresh_reveal(). - * - * @param cls closure - * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param noreveal_index choice by the mint in the cut-and-choose protocol, - * UINT16_MAX on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -typedef void -(*TALER_MINT_RefreshMeltCallback) (void *cls, - unsigned int http_status, - uint16_t noreveal_index, - json_t *full_response); - - -/** - * Submit a melt request to the mint and get the mint's - * response. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, the provided - * argument should have been constructed using - * #TALER_MINT_refresh_prepare and committed to persistent storage - * prior to calling this function. - * - * @param mint the mint handle; the mint must be ready to operate - * @param refresh_data_length size of the @a refresh_data (returned - * in the `res_size` argument from #TALER_MINT_refresh_prepare()) - * @param refresh_data the refresh data as returned from - #TALER_MINT_refresh_prepare()) - * @param melt_cb the callback to call with the result - * @param melt_cb_cls closure for @a melt_cb - * @return a handle for this request; NULL if the argument was invalid. - * In this case, neither callback will be called. - */ -struct TALER_MINT_RefreshMeltHandle * -TALER_MINT_refresh_melt (struct TALER_MINT_Handle *mint, - size_t refresh_data_length, - const char *refresh_data, - TALER_MINT_RefreshMeltCallback melt_cb, - void *melt_cb_cls); - - -/** - * Cancel a refresh melt request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param rmh the refresh handle - */ -void -TALER_MINT_refresh_melt_cancel (struct TALER_MINT_RefreshMeltHandle *rmh); - - -/* ********************* /refresh/reveal ***************************** */ - - -/** - * Callbacks of this type are used to return the final result of - * submitting a refresh request to a mint. If the operation was - * successful, this function returns the signatures over the coins - * that were remelted. The @a coin_privs and @a sigs arrays give the - * coins in the same order (and should have the same length) in which - * the original request specified the respective denomination keys. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param sigs array of signature over @a num_coins coins, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -typedef void -(*TALER_MINT_RefreshRevealCallback) (void *cls, - unsigned int http_status, - - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - json_t *full_response); - - -/** - * @brief A /refresh/reveal Handle - */ -struct TALER_MINT_RefreshRevealHandle; - - -/** - * Submit a /refresh/reval request to the mint and get the mint's - * response. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, the provided - * arguments should have been committed to persistent storage - * prior to calling this function. - * - * @param mint the mint handle; the mint must be ready to operate - * @param refresh_data_length size of the @a refresh_data (returned - * in the `res_size` argument from #TALER_MINT_refresh_prepare()) - * @param refresh_data the refresh data as returned from - #TALER_MINT_refresh_prepare()) - * @param noreveal_index response from the mint to the - * #TALER_MINT_refresh_melt() invocation - * @param reveal_cb the callback to call with the final result of the - * refresh operation - * @param reveal_cb_cls closure for the above callback - * @return a handle for this request; NULL if the argument was invalid. - * In this case, neither callback will be called. - */ -struct TALER_MINT_RefreshRevealHandle * -TALER_MINT_refresh_reveal (struct TALER_MINT_Handle *mint, - size_t refresh_data_length, - const char *refresh_data, - uint16_t noreveal_index, - TALER_MINT_RefreshRevealCallback reveal_cb, - void *reveal_cb_cls); - - -/** - * Cancel a refresh reveal request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param rrh the refresh reval handle - */ -void -TALER_MINT_refresh_reveal_cancel (struct TALER_MINT_RefreshRevealHandle *rrh); - - -/* ********************* /refresh/link ***************************** */ - - -/** - * @brief A /refresh/link Handle - */ -struct TALER_MINT_RefreshLinkHandle; - - -/** - * Callbacks of this type are used to return the final result of - * submitting a /refresh/link request to a mint. If the operation was - * successful, this function returns the signatures over the coins - * that were created when the original coin was melted. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param sigs array of signature over @a num_coins coins, NULL on error - * @param pubs array of public keys for the @a sigs, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -typedef void -(*TALER_MINT_RefreshLinkCallback) (void *cls, - unsigned int http_status, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const struct TALER_DenominationPublicKey *pubs, - json_t *full_response); - - -/** - * Submit a link request to the mint and get the mint's response. - * - * This API is typically not used by anyone, it is more a threat - * against those trying to receive a funds transfer by abusing the - * /refresh protocol. - * - * @param mint the mint handle; the mint must be ready to operate - * @param coin_priv private key to request link data for - * @param link_cb the callback to call with the useful result of the - * refresh operation the @a coin_priv was involved in (if any) - * @param link_cb_cls closure for @a link_cb - * @return a handle for this request - */ -struct TALER_MINT_RefreshLinkHandle * -TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - TALER_MINT_RefreshLinkCallback link_cb, - void *link_cb_cls); - - -/** - * Cancel a refresh link request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param rlh the refresh link handle - */ -void -TALER_MINT_refresh_link_cancel (struct TALER_MINT_RefreshLinkHandle *rlh); - - -/* ********************* /admin/add/incoming *********************** */ - - -/** - * @brief A /admin/add/incoming Handle - */ -struct TALER_MINT_AdminAddIncomingHandle; - - -/** - * Callbacks of this type are used to serve the result of submitting - * information about an incoming transaction to a mint. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param full_response full response from the mint (for logging, in case of errors) - */ -typedef void -(*TALER_MINT_AdminAddIncomingResultCallback) (void *cls, - unsigned int http_status, - json_t *full_response); - - -/** - * Notify the mint that we have received an incoming transaction - * which fills a reserve. Note that this API is an administrative - * API and thus not accessible to typical mint clients, but only - * to the operators of the mint. - * - * @param mint the mint handle; the mint must be ready to operate - * @param reserve_pub public key of the reserve - * @param amount amount that was deposited - * @param execution_date when did we receive the amount - * @param wire wire details - * @param res_cb the callback to call when the final result for this request is available - * @param res_cb_cls closure for the above callback - * @return NULL - * if the inputs are invalid (i.e. invalid amount). - * In this case, the callback is not called. - */ -struct TALER_MINT_AdminAddIncomingHandle * -TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_date, - const json_t *wire, - TALER_MINT_AdminAddIncomingResultCallback res_cb, - void *res_cb_cls); - - -/** - * Cancel an add incoming. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param aai the admin add incoming request handle - */ -void -TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai); - - -/* ********************* /wire/deposits *********************** */ - -/** - * @brief A /wire/deposits Handle - */ -struct TALER_MINT_WireDepositsHandle; - - -/** - * Details for one of the /deposit operations that the - * mint combined into a single wire transfer. - */ -struct TALER_WireDepositDetails -{ - /** - * Hash of the contract. - */ - struct GNUNET_HashCode h_contract; - - /** - * Which coin was deposited? - */ - struct TALER_CoinSpendPublicKeyP coin_pub; - - /** - * Value of the deposit (including fee). - */ - struct TALER_Amount coin_value; - - /** - * Fee charged by the mint for the deposit. - */ - struct TALER_Amount coin_fee; - - /** - * Merchant's transaction identifier. - */ - uint64_t transaction_id; - -}; - - -/** - * Function called with detailed wire transfer data, including all - * of the coin transactions that were combined into the wire transfer. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid extracted wire transfer identifier, or NULL if the mint could - * not provide any (set only if @a http_status is #MHD_HTTP_OK) - * @param total_amount total amount of the wire transfer, or NULL if the mint could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - * @param details_length length of the @a details array - * @param details array with details about the combined transactions - */ -typedef void -(*TALER_MINT_WireDepositsCallback)(void *cls, - unsigned int http_status, - json_t *json, - const struct GNUNET_HashCode *h_wire, - const struct TALER_Amount *total_amount, - unsigned int details_length, - const struct TALER_WireDepositDetails *details); - - -/** - * Query the mint about which transactions were combined - * to create a wire transfer. - * - * @param mint mint to query - * @param wtid raw wire transfer identifier to get information about - * @param cb callback to call - * @param cb_cls closure for @a cb - * @return handle to cancel operation - */ -struct TALER_MINT_WireDepositsHandle * -TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint, - const struct TALER_WireTransferIdentifierRawP *wtid, - TALER_MINT_WireDepositsCallback cb, - void *cb_cls); - - -/** - * Cancel wire deposits request. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param wdh the wire deposits request handle - */ -void -TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh); - - -/* ********************* /deposit/wtid *********************** */ - - -/** - * @brief A /deposit/wtid Handle - */ -struct TALER_MINT_DepositWtidHandle; - - -/** - * Function called with detailed wire transfer data. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid wire transfer identifier used by the mint, NULL if mint did not - * yet execute the transaction - * @param execution_time actual or planned execution time for the wire transfer - * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL) - */ -typedef void -(*TALER_MINT_DepositWtidCallback)(void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_Amount *coin_contribution); - - -/** - * Obtain the wire transfer details for a given deposit. - * - * @param mint the mint to query - * @param merchant_priv the merchant's private key - * @param h_wire hash of merchant's wire transfer details - * @param h_contract hash of the contract - * @param coin_pub public key of the coin - * @param transaction_id transaction identifier - * @param cb function to call with the result - * @param cb_cls closure for @a cb - * @return handle to abort request - */ -struct TALER_MINT_DepositWtidHandle * -TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint, - const struct TALER_MerchantPrivateKeyP *merchant_priv, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - uint64_t transaction_id, - TALER_MINT_DepositWtidCallback cb, - void *cb_cls); - - -/** - * Cancel deposit wtid request. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param dwh the wire deposits request handle - */ -void -TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh); - - -#endif /* _TALER_MINT_SERVICE_H */ diff --git a/src/include/taler_mintdb_lib.h b/src/include/taler_mintdb_lib.h deleted file mode 100644 index 70e314d9a..000000000 --- a/src/include/taler_mintdb_lib.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file include/taler_mintdb_lib.h - * @brief IO operations for the mint's private keys - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINTDB_LIB_H -#define TALER_MINTDB_LIB_H - -#include "taler_signatures.h" - -/** - * Subdirectroy under the mint's base directory which contains - * the mint's signing keys. - */ -#define TALER_MINTDB_DIR_SIGNING_KEYS "signkeys" - -/** - * Subdirectory under the mint's base directory which contains - * the mint's denomination keys. - */ -#define TALER_MINTDB_DIR_DENOMINATION_KEYS "denomkeys" - -/** - * Subdirectory under the mint's base directory which contains - * the mint's auditing information. - */ -#define TALER_MINTDB_DIR_AUDITORS "auditors" - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * @brief On disk format used for a mint signing key. Signing keys are used - * by the mint to affirm its messages, but not to create coins. - * Includes the private key followed by the public information about - * the signing key. - */ -struct TALER_MINTDB_PrivateSigningKeyInformationP -{ - /** - * Private key part of the mint's signing key. - */ - struct TALER_MintPrivateKeyP signkey_priv; - - /** - * Public information about a mint signing key. - */ - struct TALER_MintSigningKeyValidityPS issue; -}; - - -/** - * Information about a denomination key. - */ -struct TALER_MINTDB_DenominationKeyInformationP -{ - - /** - * Signature over this struct to affirm the validity of the key. - */ - struct TALER_MasterSignatureP signature; - - /** - * Signed properties of the denomination key. - */ - struct TALER_DenominationKeyValidityPS properties; -}; - - -GNUNET_NETWORK_STRUCT_END - - -/** - * @brief All information about a denomination key (which is used to - * sign coins into existence). - */ -struct TALER_MINTDB_DenominationKeyIssueInformation -{ - /** - * The private key of the denomination. Will be NULL if the private - * key is not available (this is the case after the key has expired - * for signing coins, but is still valid for depositing coins). - */ - struct TALER_DenominationPrivateKey denom_priv; - - /** - * Decoded denomination public key (the hash of it is in - * @e issue, but we sometimes need the full public key as well). - */ - struct TALER_DenominationPublicKey denom_pub; - - /** - * Signed public information about a denomination key. - */ - struct TALER_MINTDB_DenominationKeyInformationP issue; -}; - - -/** - * @brief Iterator over signing keys. - * - * @param cls closure - * @param filename name of the file the key came from - * @param ski the sign key - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -typedef int -(*TALER_MINTDB_SigningKeyIterator)(void *cls, - const char *filename, - const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski); - - -/** - * Call @a it for each signing key found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_SIGNING_KEYS - * subdirectory - * @param it function to call on each signing key - * @param it_cls closure for @a it - * @return number of files found (may not match - * number of keys given to @a it as malformed - * files are simply skipped), -1 on error - */ -int -TALER_MINTDB_signing_keys_iterate (const char *mint_base_dir, - TALER_MINTDB_SigningKeyIterator it, - void *it_cls); - - - -/** - * @brief Iterator over denomination keys. - * - * @param cls closure - * @param dki the denomination key - * @param alias coin alias - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -typedef int -(*TALER_MINTDB_DenominationKeyIterator)(void *cls, - const char *alias, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki); - - -/** - * Call @a it for each denomination key found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS - * subdirectory - * @param it function to call on each denomination key found - * @param it_cls closure for @a it - * @return -1 on error, 0 if no files were found, otherwise - * a positive number (however, even with a positive - * number it is possible that @a it was never called - * as maybe none of the files were well-formed) - */ -int -TALER_MINTDB_denomination_keys_iterate (const char *mint_base_dir, - TALER_MINTDB_DenominationKeyIterator it, - void *it_cls); - - -/** - * Exports a denomination key to the given file. - * - * @param filename the file where to write the denomination key - * @param dki the denomination key - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. - */ -int -TALER_MINTDB_denomination_key_write (const char *filename, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki); - - -/** - * Import a denomination key from the given file. - * - * @param filename the file to import the key from - * @param[out] dki set to the imported denomination key - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -int -TALER_MINTDB_denomination_key_read (const char *filename, - struct TALER_MINTDB_DenominationKeyIssueInformation *dki); - - -/** - * @brief Iterator over auditor information. - * - * @param cls closure - * @param apub the auditor's public key - * @param mpub the mint's public key (as expected by the auditor) - * @param dki_len length of @a asig and @a dki arrays - * @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len - * @param dki array of denomination coin data signed by the auditor, of length @a dki_len - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -typedef int -(*TALER_MINTDB_AuditorIterator)(void *cls, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_DenominationKeyValidityPS *dki); - - -/** - * Call @a it with information for each auditor found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS - * subdirectory - * @param it function to call with auditor information - * @param it_cls closure for @a it - * @return -1 on error, 0 if no files were found, otherwise - * a positive number (however, even with a positive - * number it is possible that @a it was never called - * as maybe none of the files were well-formed) - */ -int -TALER_MINTDB_auditor_iterate (const char *mint_base_dir, - TALER_MINTDB_AuditorIterator it, - void *it_cls); - - -/** - * Write auditor information to the given file. - * - * @param filename the file where to write the auditor information to - * @param apub the auditor's public key - * @param asigs the auditor's signatures, array of length @a dki_len - * @param mpub the mint's public key (as expected by the auditor) - * @param dki_len length of @a dki and @a asigs arrays - * @param dki array of denomination coin data signed by the auditor - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. - */ -int -TALER_MINTDB_auditor_write (const char *filename, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_DenominationKeyValidityPS *dki); - - -/** - * Initialize the plugin. - * - * @param cfg configuration to use - * @return NULL on failure - */ -struct TALER_MINTDB_Plugin * -TALER_MINTDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Shutdown the plugin. - * - * @param plugin plugin to unload - */ -void -TALER_MINTDB_plugin_unload (struct TALER_MINTDB_Plugin *plugin); - - - -#endif diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h deleted file mode 100644 index b65b3e4f7..000000000 --- a/src/include/taler_mintdb_plugin.h +++ /dev/null @@ -1,1431 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file include/taler_mintdb_plugin.h - * @brief Low-level (statement-level) database access for the mint - * @author Florian Dold - * @author Christian Grothoff - */ -#ifndef TALER_MINTDB_PLUGIN_H -#define TALER_MINTDB_PLUGIN_H - -#include <gnunet/gnunet_util_lib.h> -#include "taler_mintdb_lib.h" - - -/** - * @brief Information we keep on bank transfer(s) that established a reserve. - */ -struct TALER_MINTDB_BankTransfer -{ - - /** - * Public key of the reserve that was filled. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Amount that was transferred to the mint. - */ - struct TALER_Amount amount; - - /** - * When did the mint receive the incoming transaction? - * (This is the execution date of the mint's database, - * the execution date of the bank should be in @e wire). - */ - struct GNUNET_TIME_Absolute execution_date; - - /** - * Detailed wire information about the transaction. - */ - json_t *wire; - -}; - - -/** - * @brief A summary of a Reserve - */ -struct TALER_MINTDB_Reserve -{ - /** - * The reserve's public key. This uniquely identifies the reserve - */ - struct TALER_ReservePublicKeyP pub; - - /** - * The balance amount existing in the reserve - */ - struct TALER_Amount balance; - - /** - * The expiration date of this reserve - */ - struct GNUNET_TIME_Absolute expiry; -}; - - -/** - * @brief Information we keep for a withdrawn coin to reproduce - * the /withdraw operation if needed, and to have proof - * that a reserve was drained by this amount. - */ -struct TALER_MINTDB_CollectableBlindcoin -{ - - /** - * Our signature over the (blinded) coin. - */ - struct TALER_DenominationSignature sig; - - /** - * Denomination key (which coin was generated). - */ - struct TALER_DenominationPublicKey denom_pub; - - /** - * Value of the coin being minted (matching the denomination key) - * plus the transaction fee. We include this in what is being - * signed so that we can verify a reserve's remaining total balance - * without needing to access the respective denomination key - * information each time. - */ - struct TALER_Amount amount_with_fee; - - /** - * Withdrawl fee charged by the mint. This must match the Mint's - * denomination key's withdrawl fee. If the client puts in an - * invalid withdrawl fee (too high or too low) that does not match - * the Mint's denomination key, the withdraw operation is invalid - * and will be rejected by the mint. The @e amount_with_fee minus - * the @e withdraw_fee is must match the value of the generated - * coin. We include this in what is being signed so that we can - * verify a mint's accounting without needing to access the - * respective denomination key information each time. - */ - struct TALER_Amount withdraw_fee; - - /** - * Public key of the reserve that was drained. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Hash over the blinded message, needed to verify - * the @e reserve_sig. - */ - struct GNUNET_HashCode h_coin_envelope; - - /** - * Signature confirming the withdrawl, matching @e reserve_pub, - * @e denom_pub and @e h_coin_envelope. - */ - struct TALER_ReserveSignatureP reserve_sig; -}; - - - -/** - * @brief Types of operations on a reserved. - */ -enum TALER_MINTDB_ReserveOperation -{ - /** - * Money was deposited into the reserve via a bank transfer. - */ - TALER_MINTDB_RO_BANK_TO_MINT = 0, - - /** - * A Coin was withdrawn from the reserve using /withdraw. - */ - TALER_MINTDB_RO_WITHDRAW_COIN = 1 -}; - - -/** - * @brief Reserve history as a linked list. Lists all of the transactions - * associated with this reserve (such as the bank transfers that - * established the reserve and all /withdraw operations we have done - * since). - */ -struct TALER_MINTDB_ReserveHistory -{ - - /** - * Next entry in the reserve history. - */ - struct TALER_MINTDB_ReserveHistory *next; - - /** - * Type of the event, determins @e details. - */ - enum TALER_MINTDB_ReserveOperation type; - - /** - * Details of the operation, depending on @e type. - */ - union - { - - /** - * Details about a bank transfer to the mint. - */ - struct TALER_MINTDB_BankTransfer *bank; - - /** - * Details about a /withdraw operation. - */ - struct TALER_MINTDB_CollectableBlindcoin *withdraw; - - } details; - -}; - - -/** - * @brief Specification for a /deposit operation. The combination of - * the coin's public key, the merchant's public key and the - * transaction ID must be unique. While a coin can (theoretically) be - * deposited at the same merchant twice (with partial spending), the - * merchant must either use a different public key or a different - * transaction ID for the two transactions. The same coin must not - * be used twice at the same merchant for the same transaction - * (as determined by transaction ID). (Note: we might want to - * fix #3819 and include at least h_contract as well.) - */ -struct TALER_MINTDB_Deposit -{ - /** - * Information about the coin that is being deposited. - */ - struct TALER_CoinPublicInfo coin; - - /** - * ECDSA signature affirming that the customer intends - * this coin to be deposited at the merchant identified - * by @e h_wire in relation to the contract identified - * by @e h_contract. - */ - struct TALER_CoinSpendSignatureP csig; - - /** - * Public key of the merchant. Enables later identification - * of the merchant in case of a need to rollback transactions. - */ - struct TALER_MerchantPublicKeyP merchant_pub; - - /** - * Hash over the contract between merchant and customer - * (remains unknown to the Mint). - */ - struct GNUNET_HashCode h_contract; - - /** - * Hash of the (canonical) representation of @e wire, used - * to check the signature on the request. Generated by - * the mint from the detailed wire data provided by the - * merchant. - */ - struct GNUNET_HashCode h_wire; - - /** - * Detailed wire information for executing the transaction. - */ - json_t *wire; - - /** - * Merchant-generated transaction ID to detect duplicate - * transactions. - */ - uint64_t transaction_id; - - /** - * Time when this request was generated. Used, for example, to - * assess when (roughly) the income was achieved for tax purposes. - * Note that the Mint will only check that the timestamp is not "too - * far" into the future (i.e. several days). The fact that the - * timestamp falls within the validity period of the coin's - * denomination key is irrelevant for the validity of the deposit - * request, as obviously the customer and merchant could conspire to - * set any timestamp. Also, the Mint must accept very old deposit - * requests, as the merchant might have been unable to transmit the - * deposit request in a timely fashion (so back-dating is not - * prevented). - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * How much time does the merchant have to issue a refund request? - * Zero if refunds are not allowed. After this time, the coin - * cannot be refunded. - */ - struct GNUNET_TIME_Absolute refund_deadline; - - /** - * How much time does the merchant have to execute the wire transfer? - * This time is advisory for aggregating transactions, not a hard - * constraint (as the merchant can theoretically pick any time, - * including one in the past). - */ - struct GNUNET_TIME_Absolute wire_deadline; - - /** - * Fraction of the coin's remaining value to be deposited, including - * depositing fee (if any). The coin is identified by @e coin_pub. - */ - struct TALER_Amount amount_with_fee; - - /** - * Depositing fee. - */ - struct TALER_Amount deposit_fee; - -}; - - -/** - * @brief Global information for a refreshing session. Includes - * dimensions of the operation, security parameters and - * client signatures from "/refresh/melt" and "/refresh/commit". - */ -struct TALER_MINTDB_RefreshSession -{ - - /** - * Number of coins we are melting. - */ - uint16_t num_oldcoins; - - /** - * Number of new coins we are creating. - */ - uint16_t num_newcoins; - - /** - * Index (smaller #TALER_CNC_KAPPA) which the mint has chosen to not - * have revealed during cut and choose. - */ - uint16_t noreveal_index; - -}; - - -/** - * @brief Specification for coin in a /refresh/melt operation. - */ -struct TALER_MINTDB_RefreshMelt -{ - /** - * Information about the coin that is being melted. - */ - struct TALER_CoinPublicInfo coin; - - /** - * Signature over the melting operation. - */ - struct TALER_CoinSpendSignatureP coin_sig; - - /** - * Hash of the refresh session this coin is melted into. - */ - struct GNUNET_HashCode session_hash; - - /** - * How much value is being melted? This amount includes the fees, - * so the final amount contributed to the melt is this value minus - * the fee for melting the coin. We include the fee in what is - * being signed so that we can verify a reserve's remaining total - * balance without needing to access the respective denomination key - * information each time. - */ - struct TALER_Amount amount_with_fee; - - /** - * Melting fee charged by the mint. This must match the Mint's - * denomination key's melting fee. If the client puts in an invalid - * melting fee (too high or too low) that does not match the Mint's - * denomination key, the melting operation is invalid and will be - * rejected by the mint. The @e amount_with_fee minus the @e - * melt_fee is the amount that will be credited to the melting - * session. - */ - struct TALER_Amount melt_fee; - -}; - - -/** - * @brief We have as many `struct TALER_MINTDB_RefreshCommitCoin` as there are new - * coins being created by the refresh (for each of the #TALER_CNC_KAPPA - * sets). These are the coins we ask the mint to sign if the - * respective set is selected. - */ -struct TALER_MINTDB_RefreshCommitCoin -{ - - /** - * Encrypted data allowing those able to decrypt it to derive - * the private keys of the new coins created by the refresh. - */ - struct TALER_RefreshLinkEncrypted *refresh_link; - - /** - * Blinded message to be signed (in envelope), with @e coin_env_size bytes. - */ - char *coin_ev; - - /** - * Number of bytes in @e coin_ev. - */ - size_t coin_ev_size; - -}; - - -/** - * @brief Linked list of refresh information linked to a coin. - */ -struct TALER_MINTDB_LinkDataList -{ - /** - * Information is stored in a NULL-terminated linked list. - */ - struct TALER_MINTDB_LinkDataList *next; - - /** - * Link data, used to recover the private key of the coin - * by the owner of the old coin. - */ - struct TALER_RefreshLinkEncrypted *link_data_enc; - - /** - * Denomination public key, determines the value of the coin. - */ - struct TALER_DenominationPublicKey denom_pub; - - /** - * Signature over the blinded envelope. - */ - struct TALER_DenominationSignature ev_sig; -}; - - -/** - * @brief Enumeration to classify the different types of transactions - * that can be done with a coin. - */ -enum TALER_MINTDB_TransactionType -{ - /** - * /deposit operation. - */ - TALER_MINTDB_TT_DEPOSIT = 0, - - /** - * /refresh/melt operation. - */ - TALER_MINTDB_TT_REFRESH_MELT = 1 - -}; - - -/** - * @brief List of transactions we performed for a particular coin. - */ -struct TALER_MINTDB_TransactionList -{ - - /** - * Next pointer in the NULL-terminated linked list. - */ - struct TALER_MINTDB_TransactionList *next; - - /** - * Type of the transaction, determines what is stored in @e details. - */ - enum TALER_MINTDB_TransactionType type; - - /** - * Details about the transaction, depending on @e type. - */ - union - { - - /** - * Details if transaction was a /deposit operation. - */ - struct TALER_MINTDB_Deposit *deposit; - - /** - * Details if transaction was a /refresh/melt operation. - */ - struct TALER_MINTDB_RefreshMelt *melt; - - } details; - -}; - - -/** - * @brief All of the information from a /refresh/melt commitment. - */ -struct TALER_MINTDB_MeltCommitment -{ - - /** - * Number of coins we are melting. - */ - uint16_t num_oldcoins; - - /** - * Number of new coins we are creating. - */ - uint16_t num_newcoins; - - /** - * Array of @e num_oldcoins melt operation details. - */ - struct TALER_MINTDB_RefreshMelt *melts; - - /** - * Array of @e num_newcoins denomination keys - */ - struct TALER_DenominationPublicKey *denom_pubs; - - /** - * 2D-Array of #TALER_CNC_KAPPA and @e num_newcoins commitments. - */ - struct TALER_MINTDB_RefreshCommitCoin *commit_coins[TALER_CNC_KAPPA]; - - /** - * 2D-Array of #TALER_CNC_KAPPA and @e new_oldcoins links. - */ - struct TALER_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA]; -}; - - -/** - * @brief Handle for a database session (per-thread, for transactions). - */ -struct TALER_MINTDB_Session; - - -/** - * Function called with details about deposits that - * have been made, with the goal of executing the - * corresponding wire transaction. - * - * @param cls closure - * @param rowid unique ID for the deposit in our DB, used for marking - * it as 'tiny' or 'done' - * @param merchant_pub public key of the merchant - * @param coin_pub public key of the coin - * @param amount_with_fee amount that was deposited including fee - * @param deposit_fee amount the mint gets to keep as transaction fees - * @param transaction_id unique transaction ID chosen by the merchant - * @param h_contract hash of the contract between merchant and customer - * @param wire_deadline by which the merchant adviced that he would like the - * wire transfer to be executed - * @param wire wire details for the merchant, NULL from iterate_matching_deposits() - * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop - */ -typedef int -(*TALER_MINTDB_DepositIterator)(void *cls, - unsigned long long rowid, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - uint64_t transaction_id, - const struct GNUNET_HashCode *h_contract, - struct GNUNET_TIME_Absolute wire_deadline, - const json_t *wire); - - -/** - * Function called with the session hashes and transfer secret - * information for a given coin. - * - * @param cls closure - * @param session_hash a session the coin was melted in - * @param transfer_pub public transfer key for the session - * @param shared_secret_enc set to shared secret for the session - */ -typedef void -(*TALER_MINTDB_TransferDataCallback)(void *cls, - const struct GNUNET_HashCode *session_hash, - const struct TALER_TransferPublicKeyP *transfer_pub, - const struct TALER_EncryptedLinkSecretP *shared_secret_enc); - - -/** - * Function called with the results of the lookup of the - * wire transfer identifier information. Only called if - * we are at least aware of the transaction existing. - * - * @param cls closure - * @param wtid wire transfer identifier, NULL - * if the transaction was not yet done - * @param coin_contribution how much did the coin we asked about - * contribute to the total transfer value? (deposit value including fee) - * @param coin_fee how much did the mint charge for the deposit fee - * @param execution_time when was the transaction done, or - * when we expect it to be done (if @a wtid was NULL) - */ -typedef void -(*TALER_MINTDB_DepositWtidCallback)(void *cls, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_Amount *coin_contribution, - const struct TALER_Amount *coin_fee, - struct GNUNET_TIME_Absolute execution_time); - - -/** - * Function called with the results of the lookup of the - * transaction data associated with a wire transfer identifier. - * - * @param cls closure - * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param h_contract which contract was this payment about - * @param transaction_id merchant's transaction ID for the payment - * @param coin_pub which public key was this payment about - * @param coin_value amount contributed by this coin in total (with fee) - * @param coin_fee applicable fee for this coin - */ -typedef void -(*TALER_MINTDB_WireTransferDataCallback)(void *cls, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_value, - const struct TALER_Amount *coin_fee); - - -/** - * Callback with data about a prepared transaction. - * - * @param cls closure - * @param rowid row identifier used to mark prepared transaction as done - * @param buf transaction data that was persisted, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -typedef void -(*TALER_MINTDB_WirePreparationCallback) (void *cls, - unsigned long long rowid, - const char *buf, - size_t buf_size); - - -/** - * @brief The plugin API, returned from the plugin's "init" function. - * The argument given to "init" is simply a configuration handle. - */ -struct TALER_MINTDB_Plugin -{ - - /** - * Closure for all callbacks. - */ - void *cls; - - /** - * Name of the library which generated this plugin. Set by the - * plugin loader. - */ - char *library_name; - - /** - * Get the thread-local database-handle. - * Connect to the db if the connection does not exist yet. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the - * database default one - * @param the database connection, or NULL on error - */ - struct TALER_MINTDB_Session * - (*get_session) (void *cls, - int temporary); - - - /** - * Drop the temporary taler schema. This is only useful for testcases. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ - int - (*drop_temporary) (void *cls, - struct TALER_MINTDB_Session *db); - - - /** - * Create the necessary tables if they are not present - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param temporary should we use a temporary schema - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ - int - (*create_tables) (void *cls, - int temporary); - - - /** - * Start a transaction. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @return #GNUNET_OK on success - */ - int - (*start) (void *cls, - struct TALER_MINTDB_Session *session); - - - /** - * Commit a transaction. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @return #GNUNET_OK on success, #GNUNET_NO if the transaction - * can be retried, #GNUNET_SYSERR on hard failures - */ - int - (*commit) (void *cls, - struct TALER_MINTDB_Session *session); - - - /** - * Abort/rollback a transaction. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - */ - void - (*rollback) (void *cls, - struct TALER_MINTDB_Session *session); - - - /** - * Insert information about a denomination key and in particular - * the properties (value, fees, expiration times) the coins signed - * with this key have. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @param denom_pub the public key used for signing coins of this denomination - * @param issue issuing information with value, fees and other info about the coin - * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure - */ - int - (*insert_denomination_info) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_MINTDB_DenominationKeyInformationP *issue); - - - /** - * Fetch information about a denomination key. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @param denom_pub the public key used for signing coins of this denomination - * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL - * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure - */ - int - (*get_denomination_info) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_DenominationPublicKey *denom_pub, - struct TALER_MINTDB_DenominationKeyInformationP *issue); - - - /** - * Get the summary of a reserve. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param db the database connection handle - * @param[in,out] reserve the reserve data. The public key of the reserve should be set - * in this structure; it is used to query the database. The balance - * and expiration are then filled accordingly. - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ - int - (*reserve_get) (void *cls, - struct TALER_MINTDB_Session *db, - struct TALER_MINTDB_Reserve *reserve); - - - /** - * Insert a incoming transaction into reserves. New reserves are - * also created through this function. Note that this API call - * starts (and stops) its own transaction scope (so the application - * must not do so). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param db the database connection handle - * @param reserve_pub public key of the reserve - * @param balance the amount that has to be added to the reserve - * @param execution_time when was the amount added - * @param details bank transaction details justifying the increment, - * must be unique for each incoming transaction - * @return #GNUNET_OK upon success; #GNUNET_NO if the given - * @a details are already known for this @a reserve_pub, - * #GNUNET_SYSERR upon failures (DB error, incompatible currency) - */ - int - (*reserves_in_insert) (void *cls, - struct TALER_MINTDB_Session *db, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *balance, - struct GNUNET_TIME_Absolute execution_time, - const json_t *details); - - - /** - * Locate the response for a /withdraw request under the - * key of the hash of the blinded message. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param h_blind hash of the blinded coin to be signed (will match - * `h_coin_envelope` in the @a collectable to be returned) - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ - int - (*get_withdraw_info) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_blind, - struct TALER_MINTDB_CollectableBlindcoin *collectable); - - - /** - * Store collectable bit coin under the corresponding - * hash of the blinded message. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ - int - (*insert_withdraw_info) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_CollectableBlindcoin *collectable); - - - /** - * Get all of the transaction history associated with the specified - * reserve. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @param reserve_pub public key of the reserve - * @return known transaction history (NULL if reserve is unknown) - */ - struct TALER_MINTDB_ReserveHistory * - (*get_reserve_history) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_ReservePublicKeyP *reserve_pub); - - - /** - * Free memory associated with the given reserve history. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param rh history to free. - */ - void - (*free_reserve_history) (void *cls, - struct TALER_MINTDB_ReserveHistory *rh); - - - /** - * Check if we have the specified deposit already in the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param deposit deposit to search for - * @return #GNUNET_YES if we know this operation, - * #GNUNET_NO if this exact deposit is unknown to us, - * #GNUNET_SYSERR on DB error - */ - int - (*have_deposit) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_Deposit *deposit); - - - /** - * Insert information about deposited coin into the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit deposit information to store - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ - int - (*insert_deposit) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_Deposit *deposit); - - - /** - * Mark a deposit as tiny, thereby declaring that it cannot be - * executed by itself and should no longer be returned by - * @e iterate_ready_deposits() - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_rowid identifies the deposit row to modify - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ - int - (*mark_deposit_tiny) (void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid); - - - /** - * Mark a deposit as done, thereby declaring that it cannot be - * executed at all anymore, and should no longer be returned by - * @e iterate_ready_deposits() or @e iterate_matching_deposits(). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_rowid identifies the deposit row to modify - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ - int - (*mark_deposit_done) (void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid); - - - /** - * Obtain information about deposits that are ready to be executed. - * Such deposits must not be marked as "tiny" or "done", and the - * execution time must be in the past. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_cb function to call for ONE such deposit - * @param deposit_cb_cls closure for @a deposit_cb - * @return number of rows processed, 0 if none exist, - * #GNUNET_SYSERR on error - */ - int - (*get_ready_deposit) (void *cls, - struct TALER_MINTDB_Session *session, - TALER_MINTDB_DepositIterator deposit_cb, - void *deposit_cb_cls); - - - /** - * Obtain information about other pending deposits for the same - * destination. Those deposits must not already be "done". - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param h_wire destination of the wire transfer - * @param merchant_pub public key of the merchant - * @param deposit_cb function to call for each deposit - * @param deposit_cb_cls closure for @a deposit_cb - * @param limit maximum number of matching deposits to return - * @return number of rows processed, 0 if none exist, - * #GNUNET_SYSERR on error - */ - int - (*iterate_matching_deposits) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_wire, - const struct TALER_MerchantPublicKeyP *merchant_pub, - TALER_MINTDB_DepositIterator deposit_cb, - void *deposit_cb_cls, - uint32_t limit); - - - /** - * Lookup refresh session data under the given @a session_hash. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database handle to use - * @param session_hash hash over the melt to use for the lookup - * @param[out] refresh_session where to store the result - * @return #GNUNET_YES on success, - * #GNUNET_NO if not found, - * #GNUNET_SYSERR on DB failure - */ - int - (*get_refresh_session) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - struct TALER_MINTDB_RefreshSession *refresh_session); - - - /** - * Store new refresh session data under the given @a session_hash. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database handle to use - * @param session_hash hash over the melt to use to locate the session - * @param refresh_session session data to store - * @return #GNUNET_YES on success, - * #GNUNET_SYSERR on DB failure - */ - int - (*create_refresh_session) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - const struct TALER_MINTDB_RefreshSession *refresh_session); - - - /** - * Store the given /refresh/melt request in the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param oldcoin_index index of the coin to store - * @param melt coin melt operation details to store; includes - * the session hash of the melt - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ - int - (*insert_refresh_melt) (void *cls, - struct TALER_MINTDB_Session *session, - uint16_t oldcoin_index, - const struct TALER_MINTDB_RefreshMelt *melt); - - - /** - * Get information about melted coin details from the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param oldcoin_index index of the coin to retrieve - * @param melt melt data to fill in, can be NULL - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ - int - (*get_refresh_melt) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t oldcoin_index, - struct TALER_MINTDB_RefreshMelt *melt); - - - /** - * Store in the database which coin(s) we want to create - * in a given refresh operation. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param num_newcoins number of coins to generate, size of the @a denom_pubs array - * @param denom_pubs array denominations of the coins to create - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ - int - (*insert_refresh_order) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t num_newcoins, - const struct TALER_DenominationPublicKey *denom_pubs); - - - /** - * Lookup in the database for the @a num_newcoins coins that we want to - * create in the given refresh operation. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param num_newcoins size of the @a denom_pubs array - * @param[out] denom_pubs where to write @a num_newcoins denomination keys - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ - int - (*get_refresh_order) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t num_newcoins, - struct TALER_DenominationPublicKey *denom_pubs); - - - /** - * Store information about the commitments of the given index @a i - * for the given refresh session in the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA - * @param num_newcoins coin index size of the @a commit_coins array - * @param commit_coin array of coin commitments to store - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on error - */ - int - (*insert_refresh_commit_coins) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_newcoins, - const struct TALER_MINTDB_RefreshCommitCoin *commit_coins); - - - /** - * Obtain information about the commitment of the - * given coin of the given refresh session from the database. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose set index (1st dimension) - * @param num_coins size of the @a commit_coins array - * @param[out] commit_coins array of coin commitments to return - * @return #GNUNET_OK on success - * #GNUNET_NO if not found - * #GNUNET_SYSERR on error - */ - int - (*get_refresh_commit_coins) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_coins, - struct TALER_MINTDB_RefreshCommitCoin *commit_coins); - - - /** - * Store the commitment to the given (encrypted) refresh link data - * for the given refresh session. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA - * @param num_links size of the @a commit_link array - * @param commit_links array of link information to store - * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success - */ - int - (*insert_refresh_commit_links) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_links, - const struct TALER_RefreshCommitLinkP *commit_links); - - /** - * Obtain the commited (encrypted) refresh link data - * for the given refresh session. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension) - * @param num_links size of the @a links array to return - * @param[out] links array link information to return - * @return #GNUNET_SYSERR on internal error, - * #GNUNET_NO if commitment was not found - * #GNUNET_OK on success - */ - int - (*get_refresh_commit_links) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_links, - struct TALER_RefreshCommitLinkP *links); - - - /** - * Get all of the information from the given melt commit operation. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @return NULL if the @a session_hash does not correspond to any known melt - * operation - */ - struct TALER_MINTDB_MeltCommitment * - (*get_melt_commitment) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash); - - - /** - * Free information about a melt commitment. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param mc melt commitment data to free - */ - void - (*free_melt_commitment) (void *cls, - struct TALER_MINTDB_MeltCommitment *mc); - - - /** - * Insert signature of a new coin generated during refresh into - * the database indexed by the refresh session and the index - * of the coin. This data is later used should an old coin - * be used to try to obtain the private keys during "/refresh/link". - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param newcoin_index coin index - * @param ev_sig coin signature - * @return #GNUNET_OK on success - */ - int - (*insert_refresh_out) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t newcoin_index, - const struct TALER_DenominationSignature *ev_sig); - - - /** - * Obtain the link data of a coin, that is the encrypted link - * information, the denomination keys and the signatures. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param session_hash session to get linkage data for - * @return all known link data for the session - */ - struct TALER_MINTDB_LinkDataList * - (*get_link_data_list) (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash); - - - /** - * Free memory of the link data list. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param ldl link data list to release - */ - void - (*free_link_data_list) (void *cls, - struct TALER_MINTDB_LinkDataList *ldl); - - - /** - * Obtain shared secret and transfer public key from the public key of - * the coin. This information and the link information returned by - * @e get_link_data_list() enable the owner of an old coin to determine - * the private keys of the new coins after the melt. - * - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param coin_pub public key of the coin - * @param tdc function to call for each session the coin was melted into - * @param tdc_cls closure for @a tdc - * @return #GNUNET_OK on success, - * #GNUNET_NO on failure (not found) - * #GNUNET_SYSERR on internal failure (database issue) - */ - int - (*get_transfer) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_MINTDB_TransferDataCallback tdc, - void *tdc_cls); - - - /** - * Compile a list of all (historic) transactions performed - * with the given coin (/refresh/melt and /deposit operations). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param coin_pub coin to investigate - * @return list of transactions, NULL if coin is fresh - */ - struct TALER_MINTDB_TransactionList * - (*get_coin_transactions) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub); - - - /** - * Free linked list of transactions. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param list list to free - */ - void - (*free_coin_transaction_list) (void *cls, - struct TALER_MINTDB_TransactionList *list); - - - /** - * Lookup the list of Taler transactions that was aggregated - * into a wire transfer by the respective @a raw_wtid. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection - * @param wtid the raw wire transfer identifier we used - * @param cb function to call on each transaction found - * @param cb_cls closure for @a cb - * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors, - * #GNUNET_NO if we found no results - */ - int - (*lookup_wire_transfer) (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_WireTransferIdentifierRawP *wtid, - TALER_MINTDB_WireTransferDataCallback cb, - void *cb_cls); - - - /** - * Try to find the wire transfer details for a deposit operation. - * If we did not execute the deposit yet, return when it is supposed - * to be executed. - * - * @param cls closure - * @param session database connection - * @param h_contract hash of the contract - * @param h_wire hash of merchant wire details - * @param coin_pub public key of deposited coin - * @param merchant_pub merchant public key - * @param transaction_id transaction identifier - * @param cb function to call with the result - * @param cb_cls closure to pass to @a cb - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors, - * #GNUNET_NO if nothing was found - */ - int - (*wire_lookup_deposit_wtid)(void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_MerchantPublicKeyP *merchant_pub, - uint64_t transaction_id, - TALER_MINTDB_DepositWtidCallback cb, - void *cb_cls); - - - /** - * Function called to insert aggregation information into the DB. - * - * @param cls closure - * @param session database connection - * @param wtid the raw wire transfer identifier we used - * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param h_contract which contract was this payment about - * @param transaction_id merchant's transaction ID for the payment - * @param execution_time when did we execute the transaction - * @param coin_pub which public key was this payment about - * @param coin_value amount contributed by this coin in total - * @param coin_fee deposit fee charged by mint for this coin - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ - int - (*insert_aggregation_tracking)(void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_value, - const struct TALER_Amount *coin_fee); - - - /** - * Function called to insert wire transfer commit data into the DB. - * - * @param cls closure - * @param session database connection - * @param type type of the wire transfer (i.e. "sepa") - * @param buf buffer with wire transfer preparation data - * @param buf_size number of bytes in @a buf - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ - int - (*wire_prepare_data_insert)(void *cls, - struct TALER_MINTDB_Session *session, - const char *type, - const char *buf, - size_t buf_size); - - - /** - * Function called to mark wire transfer commit data as finished. - * - * @param cls closure - * @param session database connection - * @param rowid which entry to mark as finished - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ - int - (*wire_prepare_data_mark_finished)(void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid); - - - /** - * Function called to get an unfinished wire transfer - * preparation data. Fetches at most one item. - * - * @param cls closure - * @param session database connection - * @param type type fo the wire transfer (i.e. "sepa") - * @param cb function to call for ONE unfinished item - * @param cb_cls closure for @a cb - * @return #GNUNET_OK on success, - * #GNUNET_NO if there are no entries, - * #GNUNET_SYSERR on DB errors - */ - int - (*wire_prepare_data_get)(void *cls, - struct TALER_MINTDB_Session *session, - const char *type, - TALER_MINTDB_WirePreparationCallback cb, - void *cb_cls); - - -}; - - -#endif /* _TALER_MINT_DB_H */ diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 2526597ee..729bed262 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -54,62 +54,62 @@ #define TALER_IDLE_RESERVE_EXPIRATION_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, 5) /*********************************************/ -/* Mint offline signatures (with master key) */ +/* Exchange offline signatures (with master key) */ /*********************************************/ /** - * Purpose for signing public keys signed by the mint master key. + * Purpose for signing public keys signed by the exchange master key. */ #define TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY 1024 /** - * Purpose for denomination keys signed by the mint master key. + * Purpose for denomination keys signed by the exchange master key. */ #define TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY 1025 /** - * Signature where the Mint confirms its SEPA details in + * Signature where the Exchange confirms its SEPA details in * the /wire/sepa response. */ #define TALER_SIGNATURE_MASTER_SEPA_DETAILS 1026 /*********************************************/ -/* Mint online signatures (with signing key) */ +/* Exchange online signatures (with signing key) */ /*********************************************/ /** - * Purpose for the state of a reserve, signed by the mint's signing + * Purpose for the state of a reserve, signed by the exchange's signing * key. */ -#define TALER_SIGNATURE_MINT_RESERVE_STATUS 1032 +#define TALER_SIGNATURE_EXCHANGE_RESERVE_STATUS 1032 /** - * Signature where the Mint confirms a deposit request. + * Signature where the Exchange confirms a deposit request. */ -#define TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT 1033 +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT 1033 /** - * Signature where the mint (current signing key) confirms the + * Signature where the exchange (current signing key) confirms the * no-reveal index for cut-and-choose and the validity of the melted * coins. */ -#define TALER_SIGNATURE_MINT_CONFIRM_MELT 1034 +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT 1034 /** - * Signature where the Mint confirms the full /keys response set. + * Signature where the Exchange confirms the full /keys response set. */ -#define TALER_SIGNATURE_MINT_KEY_SET 1035 +#define TALER_SIGNATURE_EXCHANGE_KEY_SET 1035 /** - * Signature where the Mint confirms the /wire response. + * Signature where the Exchange confirms the /wire response. */ -#define TALER_SIGNATURE_MINT_WIRE_TYPES 1036 +#define TALER_SIGNATURE_EXCHANGE_WIRE_TYPES 1036 /** - * Signature where the Mint confirms the /deposit/wtid response. + * Signature where the Exchange confirms the /deposit/wtid response. */ -#define TALER_SIGNATURE_MINT_CONFIRM_WIRE 1036 +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE 1036 /*********************/ @@ -118,9 +118,9 @@ /** * Signature where the auditor confirms that he is - * aware of certain denomination keys from the mint. + * aware of certain denomination keys from the exchange. */ -#define TALER_SIGNATURE_AUDITOR_MINT_KEYS 1064 +#define TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS 1064 /***********************/ @@ -176,7 +176,7 @@ /** * EdDSA test signature. */ -#define TALER_SIGNATURE_MINT_TEST_EDDSA 1303 +#define TALER_SIGNATURE_EXCHANGE_TEST_EDDSA 1303 @@ -202,7 +202,7 @@ struct TALER_WithdrawRequestPS struct TALER_ReservePublicKeyP reserve_pub; /** - * Value of the coin being minted (matching the denomination key) + * Value of the coin being exchangeed (matching the denomination key) * plus the transaction fee. We include this in what is being * signed so that we can verify a reserve's remaining total balance * without needing to access the respective denomination key @@ -211,14 +211,14 @@ struct TALER_WithdrawRequestPS struct TALER_AmountNBO amount_with_fee; /** - * Withdrawl fee charged by the mint. This must match the Mint's + * Withdrawl fee charged by the exchange. This must match the Exchange's * denomination key's withdrawl fee. If the client puts in an * invalid withdrawl fee (too high or too low) that does not match - * the Mint's denomination key, the withdraw operation is invalid - * and will be rejected by the mint. The @e amount_with_fee minus + * the Exchange's denomination key, the withdraw operation is invalid + * and will be rejected by the exchange. The @e amount_with_fee minus * the @e withdraw_fee is must match the value of the generated * coin. We include this in what is being signed so that we can - * verify a mint's accounting without needing to access the + * verify a exchange's accounting without needing to access the * respective denomination key information each time. */ struct TALER_AmountNBO withdraw_fee; @@ -229,7 +229,7 @@ struct TALER_WithdrawRequestPS struct GNUNET_HashCode h_denomination_pub GNUNET_PACKED; /** - * Hash of the (blinded) message to be signed by the Mint. + * Hash of the (blinded) message to be signed by the Exchange. */ struct GNUNET_HashCode h_coin_envelope GNUNET_PACKED; }; @@ -260,12 +260,12 @@ struct TALER_DepositRequestPS /** * Time when this request was generated. Used, for example, to * assess when (roughly) the income was achieved for tax purposes. - * Note that the Mint will only check that the timestamp is not "too + * Note that the Exchange will only check that the timestamp is not "too * far" into the future (i.e. several days). The fact that the * timestamp falls within the validity period of the coin's * denomination key is irrelevant for the validity of the deposit * request, as obviously the customer and merchant could conspire to - * set any timestamp. Also, the Mint must accept very old deposit + * set any timestamp. Also, the Exchange must accept very old deposit * requests, as the merchant might have been unable to transmit the * deposit request in a timely fashion (so back-dating is not * prevented). @@ -293,17 +293,17 @@ struct TALER_DepositRequestPS /** * Amount to be deposited, including deposit fee charged by the - * mint. This is the total amount that the coin's value at the mint + * exchange. This is the total amount that the coin's value at the exchange * will be reduced by. */ struct TALER_AmountNBO amount_with_fee; /** - * Depositing fee charged by the mint. This must match the Mint's + * Depositing fee charged by the exchange. This must match the Exchange's * denomination key's depositing fee. If the client puts in an * invalid deposit fee (too high or too low) that does not match the - * Mint's denomination key, the deposit operation is invalid and - * will be rejected by the mint. The @e amount_with_fee minus the + * Exchange's denomination key, the deposit operation is invalid and + * will be rejected by the exchange. The @e amount_with_fee minus the * @e deposit_fee is the amount that will be transferred to the * account identified by @e h_wire. */ @@ -317,7 +317,7 @@ struct TALER_DepositRequestPS /** * The coin's public key. This is the value that must have been - * signed (blindly) by the Mint. The deposit request is to be + * signed (blindly) by the Exchange. The deposit request is to be * signed by the corresponding private key (using EdDSA). */ struct TALER_CoinSpendPublicKeyP coin_pub; @@ -327,13 +327,13 @@ struct TALER_DepositRequestPS /** * @brief Format used to generate the signature on a confirmation - * from the mint that a deposit request succeeded. + * from the exchange that a deposit request succeeded. */ struct TALER_DepositConfirmationPS { /** - * Purpose must be #TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT. Signed - * by a `struct TALER_MintPublicKeyP` using EdDSA. + * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; @@ -362,7 +362,7 @@ struct TALER_DepositConfirmationPS * How much time does the @e merchant have to issue a refund * request? Zero if refunds are not allowed. After this time, the * coin cannot be refunded. Note that the wire transfer will not be - * performed by the mint until the refund deadline. This value + * performed by the exchange until the refund deadline. This value * is taken from the original deposit request. */ struct GNUNET_TIME_AbsoluteNBO refund_deadline; @@ -375,7 +375,7 @@ struct TALER_DepositConfirmationPS /** * The coin's public key. This is the value that must have been - * signed (blindly) by the Mint. The deposit request is to be + * signed (blindly) by the Exchange. The deposit request is to be * signed by the corresponding private key (using EdDSA). */ struct TALER_CoinSpendPublicKeyP coin_pub; @@ -417,11 +417,11 @@ struct TALER_RefreshMeltCoinAffirmationPS struct TALER_AmountNBO amount_with_fee; /** - * Melting fee charged by the mint. This must match the Mint's + * Melting fee charged by the exchange. This must match the Exchange's * denomination key's melting fee. If the client puts in an invalid - * melting fee (too high or too low) that does not match the Mint's + * melting fee (too high or too low) that does not match the Exchange's * denomination key, the melting operation is invalid and will be - * rejected by the mint. The @e amount_with_fee minus the @e + * rejected by the exchange. The @e amount_with_fee minus the @e * melt_fee is the amount that will be credited to the melting * session. */ @@ -429,7 +429,7 @@ struct TALER_RefreshMeltCoinAffirmationPS /** * The coin's public key. This is the value that must have been - * signed (blindly) by the Mint. The deposit request is to be + * signed (blindly) by the Exchange. The deposit request is to be * signed by the corresponding private key (using EdDSA). */ struct TALER_CoinSpendPublicKeyP coin_pub; @@ -437,16 +437,16 @@ struct TALER_RefreshMeltCoinAffirmationPS /** - * @brief Format of the block signed by the Mint in response to a successful - * "/refresh/melt" request. Hereby the mint affirms that all of the - * coins were successfully melted. This also commits the mint to a + * @brief Format of the block signed by the Exchange in response to a successful + * "/refresh/melt" request. Hereby the exchange affirms that all of the + * coins were successfully melted. This also commits the exchange to a * particular index to not be revealed during the refresh. */ struct TALER_RefreshMeltConfirmationPS { /** - * Purpose is #TALER_SIGNATURE_MINT_CONFIRM_MELT. Signed - * by a `struct TALER_MintPublicKeyP` using EdDSA. + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; @@ -469,14 +469,14 @@ struct TALER_RefreshMeltConfirmationPS /** - * @brief Information about a signing key of the mint. Signing keys are used - * to sign mint messages other than coins, i.e. to confirm that a + * @brief Information about a signing key of the exchange. Signing keys are used + * to sign exchange messages other than coins, i.e. to confirm that a * deposit was successful or that a refresh was accepted. */ -struct TALER_MintSigningKeyValidityPS +struct TALER_ExchangeSigningKeyValidityPS { /** - * Signature over the signing key (by the master key of the mint). + * Signature over the signing key (by the master key of the exchange). * * FIXME: should be moved outside of the "PS" struct, this is ugly. * (and makes this struct different from all of the others) @@ -489,8 +489,8 @@ struct TALER_MintSigningKeyValidityPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * Master public key of the mint corresponding to @e signature. - * This is the long-term offline master key of the mint. + * Master public key of the exchange corresponding to @e signature. + * This is the long-term offline master key of the exchange. */ struct TALER_MasterPublicKeyP master_public_key; @@ -501,7 +501,7 @@ struct TALER_MintSigningKeyValidityPS /** * When does this signing key expire? Note: This is currently when - * the Mint will definitively stop using it. Signatures made with + * the Exchange will definitively stop using it. Signatures made with * the key remain valid until @e end. When checking validity periods, * clients should allow for some overlap between keys and tolerate * the use of either key during the overlap time (due to the @@ -512,31 +512,31 @@ struct TALER_MintSigningKeyValidityPS /** * When do signatures with this signing key become invalid? After * this point, these signatures cannot be used in (legal) disputes - * anymore, as the Mint is then allowed to destroy its side of the + * anymore, as the Exchange is then allowed to destroy its side of the * evidence. @e end is expected to be significantly larger than @e * expire (by a year or more). */ struct GNUNET_TIME_AbsoluteNBO end; /** - * The public online signing key that the mint will use + * The public online signing key that the exchange will use * between @e start and @e expire. */ - struct TALER_MintPublicKeyP signkey_pub; + struct TALER_ExchangePublicKeyP signkey_pub; }; /** - * @brief Signature made by the mint over the full set of keys, used - * to detect cheating mints that give out different sets to + * @brief Signature made by the exchange over the full set of keys, used + * to detect cheating exchanges that give out different sets to * different users. */ -struct TALER_MintKeySetPS +struct TALER_ExchangeKeySetPS { /** - * Purpose is #TALER_SIGNATURE_MINT_KEY_SET. Signed - * by a `struct TALER_MintPublicKeyP` using EdDSA. + * Purpose is #TALER_SIGNATURE_EXCHANGE_KEY_SET. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; @@ -565,7 +565,7 @@ struct TALER_DenominationKeyValidityPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * The long-term offline master key of the mint that was + * The long-term offline master key of the exchange that was * used to create @e signature. */ struct TALER_MasterPublicKeyP master; @@ -576,14 +576,14 @@ struct TALER_DenominationKeyValidityPS struct GNUNET_TIME_AbsoluteNBO start; /** - * The mint will sign fresh coins between @e start and this time. + * The exchange will sign fresh coins between @e start and this time. * @e expire_withdraw will be somewhat larger than @e start to * ensure a sufficiently large anonymity set, while also allowing - * the Mint to limit the financial damage in case of a key being - * compromised. Thus, mints with low volume are expected to have a - * longer withdraw period (@e expire_withdraw - @e start) than mints + * the Exchange to limit the financial damage in case of a key being + * compromised. Thus, exchanges with low volume are expected to have a + * longer withdraw period (@e expire_withdraw - @e start) than exchanges * with high transaction volume. The period may also differ between - * types of coins. A mint may also have a few denomination keys + * types of coins. A exchange may also have a few denomination keys * with the same value with overlapping validity periods, to address * issues such as clock skew. */ @@ -592,7 +592,7 @@ struct TALER_DenominationKeyValidityPS /** * Coins signed with the denomination key must be spent or refreshed * between @e start and this expiration time. After this time, the - * mint will refuse transactions involving this key as it will + * exchange will refuse transactions involving this key as it will * "drop" the table with double-spending information (shortly after) * this time. Note that wallets should refresh coins significantly * before this time to be on the safe side. @e expire_spend must be @@ -604,7 +604,7 @@ struct TALER_DenominationKeyValidityPS /** * When do signatures with this denomination key become invalid? * After this point, these signatures cannot be used in (legal) - * disputes anymore, as the Mint is then allowed to destroy its side + * disputes anymore, as the Exchange is then allowed to destroy its side * of the evidence. @e expire_legal is expected to be significantly * larger than @e expire_spend (by a year or more). */ @@ -616,19 +616,19 @@ struct TALER_DenominationKeyValidityPS struct TALER_AmountNBO value; /** - * The fee the mint charges when a coin of this type is withdrawn. + * The fee the exchange charges when a coin of this type is withdrawn. * (can be zero). */ struct TALER_AmountNBO fee_withdraw; /** - * The fee the mint charges when a coin of this type is deposited. + * The fee the exchange charges when a coin of this type is deposited. * (can be zero). */ struct TALER_AmountNBO fee_deposit; /** - * The fee the mint charges when a coin of this type is refreshed. + * The fee the exchange charges when a coin of this type is refreshed. * (can be zero). */ struct TALER_AmountNBO fee_refresh; @@ -645,18 +645,18 @@ struct TALER_DenominationKeyValidityPS /** * @brief Information signed by an auditor affirming * the master public key and the denomination keys - * of a mint. + * of a exchange. */ -struct TALER_MintKeyValidityPS +struct TALER_ExchangeKeyValidityPS { /** - * Purpose is #TALER_SIGNATURE_AUDITOR_MINT_KEYS. + * Purpose is #TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * The long-term offline master key of the mint, affirmed by the + * The long-term offline master key of the exchange, affirmed by the * auditor. */ struct TALER_MasterPublicKeyP master; @@ -667,14 +667,14 @@ struct TALER_MintKeyValidityPS struct GNUNET_TIME_AbsoluteNBO start; /** - * The mint will sign fresh coins between @e start and this time. + * The exchange will sign fresh coins between @e start and this time. * @e expire_withdraw will be somewhat larger than @e start to * ensure a sufficiently large anonymity set, while also allowing - * the Mint to limit the financial damage in case of a key being - * compromised. Thus, mints with low volume are expected to have a - * longer withdraw period (@e expire_withdraw - @e start) than mints + * the Exchange to limit the financial damage in case of a key being + * compromised. Thus, exchanges with low volume are expected to have a + * longer withdraw period (@e expire_withdraw - @e start) than exchanges * with high transaction volume. The period may also differ between - * types of coins. A mint may also have a few denomination keys + * types of coins. A exchange may also have a few denomination keys * with the same value with overlapping validity periods, to address * issues such as clock skew. */ @@ -683,7 +683,7 @@ struct TALER_MintKeyValidityPS /** * Coins signed with the denomination key must be spent or refreshed * between @e start and this expiration time. After this time, the - * mint will refuse transactions involving this key as it will + * exchange will refuse transactions involving this key as it will * "drop" the table with double-spending information (shortly after) * this time. Note that wallets should refresh coins significantly * before this time to be on the safe side. @e expire_spend must be @@ -695,7 +695,7 @@ struct TALER_MintKeyValidityPS /** * When do signatures with this denomination key become invalid? * After this point, these signatures cannot be used in (legal) - * disputes anymore, as the Mint is then allowed to destroy its side + * disputes anymore, as the Exchange is then allowed to destroy its side * of the evidence. @e expire_legal is expected to be significantly * larger than @e expire_spend (by a year or more). */ @@ -707,19 +707,19 @@ struct TALER_MintKeyValidityPS struct TALER_AmountNBO value; /** - * The fee the mint charges when a coin of this type is withdrawn. + * The fee the exchange charges when a coin of this type is withdrawn. * (can be zero). */ struct TALER_AmountNBO fee_withdraw; /** - * The fee the mint charges when a coin of this type is deposited. + * The fee the exchange charges when a coin of this type is deposited. * (can be zero). */ struct TALER_AmountNBO fee_deposit; /** - * The fee the mint charges when a coin of this type is refreshed. + * The fee the exchange charges when a coin of this type is refreshed. * (can be zero). */ struct TALER_AmountNBO fee_refresh; @@ -737,7 +737,7 @@ struct TALER_MintKeyValidityPS * @brief For each (old) coin being melted, we have a `struct * RefreshCommitLinkP` that allows the user to find the shared secret * to decrypt the respective refresh links for the new coins in the - * `struct TALER_MINTDB_RefreshCommitCoin`. + * `struct TALER_EXCHANGEDB_RefreshCommitCoin`. * * Part of the construction of the refresh session's hash and * thus of what is signed there. @@ -759,8 +759,8 @@ struct TALER_RefreshCommitLinkP /** - * @brief Information signed by the mint's master - * key affirming the SEPA details for the mint. + * @brief Information signed by the exchange's master + * key affirming the SEPA details for the exchange. */ struct TALER_MasterWireSepaDetailsPS { @@ -780,19 +780,19 @@ struct TALER_MasterWireSepaDetailsPS /** - * @brief Information signed by a mint's online signing key affirming - * the wire formats supported by the mint. + * @brief Information signed by a exchange's online signing key affirming + * the wire formats supported by the exchange. */ -struct TALER_MintWireSupportMethodsPS +struct TALER_ExchangeWireSupportMethodsPS { /** - * Purpose is #TALER_SIGNATURE_MINT_WIRE_TYPES. + * Purpose is #TALER_SIGNATURE_EXCHANGE_WIRE_TYPES. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * Hash over the various wire formats supported by this mint + * Hash over the various wire formats supported by this exchange * (all as 0-terminated strings). */ struct GNUNET_HashCode h_wire_types GNUNET_PACKED; @@ -841,7 +841,7 @@ struct TALER_DepositTrackPS /** * The coin's public key. This is the value that must have been - * signed (blindly) by the Mint. + * signed (blindly) by the Exchange. */ struct TALER_CoinSpendPublicKeyP coin_pub; @@ -896,14 +896,14 @@ struct TALER_ContractPS /** - * Details affirmed by the mint about a wire transfer the mint + * Details affirmed by the exchange about a wire transfer the exchange * claims to have done with respect to a deposit operation. */ struct TALER_ConfirmWirePS { /** * Purpose header for the signature over the contract with - * purpose #TALER_SIGNATURE_MINT_CONFIRM_WIRE. + * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; @@ -924,7 +924,7 @@ struct TALER_ConfirmWirePS /** * The coin's public key. This is the value that must have been - * signed (blindly) by the Mint. + * signed (blindly) by the Exchange. */ struct TALER_CoinSpendPublicKeyP coin_pub; @@ -941,7 +941,7 @@ struct TALER_ConfirmWirePS uint64_t transaction_id GNUNET_PACKED; /** - * When did the mint execute this transfer? Note that the + * When did the exchange execute this transfer? Note that the * timestamp may not be exactly the same on the wire, i.e. * because the wire has a different timezone or resolution. */ diff --git a/src/mint-lib/Makefile.am b/src/mint-lib/Makefile.am deleted file mode 100644 index 171a42464..000000000 --- a/src/mint-lib/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -lib_LTLIBRARIES = \ - libtalermint.la - -libtalermint_la_LDFLAGS = \ - -version-info 0:0:0 \ - -no-undefined - -libtalermint_la_SOURCES = \ - mint_api_common.c mint_api_common.h \ - mint_api_context.c mint_api_context.h \ - mint_api_json.c mint_api_json.h \ - mint_api_handle.c mint_api_handle.h \ - mint_api_admin.c \ - mint_api_deposit.c \ - mint_api_deposit_wtid.c \ - mint_api_refresh.c \ - mint_api_refresh_link.c \ - mint_api_reserve.c \ - mint_api_wire.c \ - mint_api_wire_deposits.c - -libtalermint_la_LIBADD = \ - -lgnunetutil \ - -ljansson \ - $(XLIB) - -if HAVE_LIBCURL -libtalermint_la_LIBADD += -lcurl -else -if HAVE_LIBGNURL -libtalermint_la_LIBADD += -lgnurl -endif -endif - -check_PROGRAMS = \ - test_mint_api - -TESTS = \ - $(check_PROGRAMS) - -test_mint_api_SOURCES = \ - test_mint_api.c -test_mint_api_LDADD = \ - libtalermint.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetutil \ - -ljansson - -EXTRA_DIST = \ - test-mint-home/config/mint-common.conf \ - test-mint-home/master.priv \ - test-mint-home/denomkeys/ \ - test-mint-home/signkeys/ diff --git a/src/mint-lib/afl-generate.sh b/src/mint-lib/afl-generate.sh deleted file mode 100644 index 4b5051869..000000000 --- a/src/mint-lib/afl-generate.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# This file is part of TALER -# Copyright (C) 2015 GNUnet e.V. -# -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free Software -# Foundation; either version 3, or (at your option) any later version. -# -# TALER is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along with -# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -# -# -# This will generate testcases in a directory 'afl-tests', which can then -# be moved into src/mint/afl-tests/ to be run during mint-testing. -# -# This script uses American Fuzzy Loop (AFL) to fuzz the mint to -# automatically create tests with good coverage. You must install -# AFL and set AFL_HOME to the directory where AFL is installed -# before running. Also, a directory "baseline/" should exist with -# templates for inputs for AFL to fuzz. These can be generated -# by running wireshark on loopback while running 'make check' in -# this directory. Save each HTTP request to a new file. -# -# Note that you want to switch 'TESTRUN = NO' and pre-init the -# database before running this, otherwise it will be awfully slow. -# -# Must be run from this directory. -# -$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-mint-httpd -f /tmp/afl-input -d test-mint-home/ -C diff --git a/src/mint-lib/mint_api_admin.c b/src/mint-lib/mint_api_admin.c deleted file mode 100644 index 641e0690f..000000000 --- a/src/mint-lib/mint_api_admin.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_admin.c - * @brief Implementation of the /admin/ requests of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief An admin/add/incoming Handle - */ -struct TALER_MINT_AdminAddIncomingHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * HTTP headers for the request. - */ - struct curl_slist *headers; - - /** - * Function to call with the result. - */ - TALER_MINT_AdminAddIncomingResultCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - -}; - - -/** - * Function called when we're done processing the - * HTTP /admin/add/incoming request. - * - * @param cls the `struct TALER_MINT_AdminAddIncomingHandle` - * @param eh the curl request handle - */ -static void -handle_admin_add_incoming_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_AdminAddIncomingHandle *aai = cls; - long response_code; - json_t *json; - - aai->job = NULL; - json = MAC_download_get_result (&aai->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_FORBIDDEN: - /* Access denied */ - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - aai->cb (aai->cb_cls, - response_code, - json); - json_decref (json); - TALER_MINT_admin_add_incoming_cancel (aai); -} - - -/** - * Notify the mint that we have received an incoming transaction - * which fills a reserve. Note that this API is an administrative - * API and thus not accessible to typical mint clients, but only - * to the operators of the mint. - * - * @param mint the mint handle; the mint must be ready to operate - * @param reserve_pub public key of the reserve - * @param amount amount that was deposited - * @param execution_date when did we receive the amount - * @param wire wire details - * @param res_cb the callback to call when the final result for this request is available - * @param res_cb_cls closure for the above callback - * @return NULL - * if the inputs are invalid (i.e. invalid amount). - * In this case, the callback is not called. - */ -struct TALER_MINT_AdminAddIncomingHandle * -TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_date, - const json_t *wire, - TALER_MINT_AdminAddIncomingResultCallback res_cb, - void *res_cb_cls) -{ - struct TALER_MINT_AdminAddIncomingHandle *aai; - struct TALER_MINT_Context *ctx; - json_t *admin_obj; - CURL *eh; - - GNUNET_assert (GNUNET_OK == - TALER_round_abs_time (&execution_date)); - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */ - " s:o, s:O}", /* execution_Date/wire */ - "reserve_pub", TALER_json_from_data (reserve_pub, - sizeof (*reserve_pub)), - "amount", TALER_json_from_amount (amount), - "execution_date", TALER_json_from_abs (execution_date), - "wire", wire); - aai = GNUNET_new (struct TALER_MINT_AdminAddIncomingHandle); - aai->mint = mint; - aai->cb = res_cb; - aai->cb_cls = res_cb_cls; - aai->url = MAH_path_to_url (mint, "/admin/add/incoming"); - - eh = curl_easy_init (); - GNUNET_assert (NULL != (aai->json_enc = - json_dumps (admin_obj, - JSON_COMPACT))); - json_decref (admin_obj); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - aai->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - aai->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (aai->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &aai->db)); - ctx = MAH_handle_to_context (mint); - aai->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_admin_add_incoming_finished, - aai); - return aai; -} - - -/** - * Cancel an add incoming. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param aai the admin add incoming request handle - */ -void -TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai) -{ - if (NULL != aai->job) - { - MAC_job_cancel (aai->job); - aai->job = NULL; - } - curl_slist_free_all (aai->headers); - GNUNET_free_non_null (aai->db.buf); - GNUNET_free (aai->url); - GNUNET_free (aai->json_enc); - GNUNET_free (aai); -} - - -/* end of mint_api_admin.c */ diff --git a/src/mint-lib/mint_api_common.c b/src/mint-lib/mint_api_common.c deleted file mode 100644 index faba38c74..000000000 --- a/src/mint-lib/mint_api_common.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_common.c - * @brief common functions for the mint API - * @author Christian Grothoff - */ -#include "platform.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * Verify a coins transaction history as returned by the mint. - * - * @param currency expected currency for the coin - * @param coin_pub public key of the coin - * @param history history of the coin in json encoding - * @param[out] total how much of the coin has been spent according to @a history - * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not - */ -int -TALER_MINT_verify_coin_history_ (const char *currency, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - json_t *history, - struct TALER_Amount *total) -{ - size_t len; - size_t off; - - if (NULL == history) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - len = json_array_size (history); - if (0 == len) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - TALER_amount_get_zero (currency, - total); - for (off=0;off<len;off++) - { - json_t *transaction; - struct TALER_Amount amount; - struct TALER_CoinSpendSignatureP sig; - void *details; - size_t details_size; - const char *type; - struct MAJ_Specification spec[] = { - MAJ_spec_amount ("amount", - &amount), - MAJ_spec_string ("type", - &type), - MAJ_spec_fixed_auto ("signature", - &sig), - MAJ_spec_varsize ("details", - &details, - &details_size), - MAJ_spec_end - }; - - transaction = json_array_get (history, - off); - if (GNUNET_OK != - MAJ_parse_json (transaction, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 == strcasecmp (type, - "DEPOSIT")) - { - const struct TALER_DepositRequestPS *dr; - struct TALER_Amount dr_amount; - - if (details_size != sizeof (struct TALER_DepositRequestPS)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - dr = (const struct TALER_DepositRequestPS *) details; - if (details_size != ntohl (dr->purpose.size)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr->purpose, - &sig.eddsa_signature, - &coin_pub->eddsa_pub)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - - // FIXME: check sig! - TALER_amount_ntoh (&dr_amount, - &dr->amount_with_fee); - if (0 != TALER_amount_cmp (&dr_amount, - &amount)) - { - GNUNET_break (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - } - else if (0 == strcasecmp (type, - "MELT")) - { - const struct TALER_RefreshMeltCoinAffirmationPS *rm; - struct TALER_Amount rm_amount; - - if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details; - if (details_size != ntohl (rm->purpose.size)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &rm->purpose, - &sig.eddsa_signature, - &coin_pub->eddsa_pub)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - TALER_amount_ntoh (&rm_amount, - &rm->amount_with_fee); - if (0 != TALER_amount_cmp (&rm_amount, - &amount)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - } - else - { - /* signature not supported, new version on server? */ - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_amount_add (total, - total, - &amount)) - { - /* overflow in history already!? inconceivable! Bad mint! */ - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - MAJ_parse_free (spec); - } - return GNUNET_OK; -} - - -/* end of mint_api_common.c */ diff --git a/src/mint-lib/mint_api_common.h b/src/mint-lib/mint_api_common.h deleted file mode 100644 index 10a202146..000000000 --- a/src/mint-lib/mint_api_common.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_common.h - * @brief common functions for the mint API - * @author Christian Grothoff - */ -#include <jansson.h> -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" - -/** - * Verify a coins transaction history as returned by the mint. - * - * @param currency expected currency for the coin - * @param coin_pub public key of the coin - * @param history history of the coin in json encoding - * @param[out] total how much of the coin has been spent according to @a history - * @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not - */ -int -TALER_MINT_verify_coin_history_ (const char *currency, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - json_t *history, - struct TALER_Amount *total); - -/* end of mint_api_common.h */ diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c deleted file mode 100644 index 2767906b5..000000000 --- a/src/mint-lib/mint_api_context.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_context.c - * @brief Implementation of the context part of the mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include "taler_mint_service.h" -#include "mint_api_context.h" - - -/** - * Log error related to CURL operations. - * - * @param type log level - * @param function which function failed to run - * @param code what was the curl error code - */ -#define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, \ - "Curl function `%s' has failed at `%s:%d' with error: %s\n", \ - function, __FILE__, __LINE__, curl_easy_strerror (code)); - -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)\n", \ - __FILE__, __LINE__, error.text, error.source) - - -/** - * Failsafe flag. Raised if our constructor fails to initialize - * the Curl library. - */ -static int TALER_MINT_curl_fail; - - -/** - * Jobs are CURL requests running within a `struct TALER_MINT_Context`. - */ -struct MAC_Job -{ - - /** - * We keep jobs in a DLL. - */ - struct MAC_Job *next; - - /** - * We keep jobs in a DLL. - */ - struct MAC_Job *prev; - - /** - * Easy handle of the job. - */ - CURL *easy_handle; - - /** - * Context this job runs in. - */ - struct TALER_MINT_Context *ctx; - - /** - * Function to call upon completion. - */ - MAC_JobCompletionCallback jcc; - - /** - * Closure for @e jcc. - */ - void *jcc_cls; - -}; - - -/** - * Context - */ -struct TALER_MINT_Context -{ - /** - * Curl multi handle - */ - CURLM *multi; - - /** - * Curl share handle - */ - CURLSH *share; - - /** - * We keep jobs in a DLL. - */ - struct MAC_Job *jobs_head; - - /** - * We keep jobs in a DLL. - */ - struct MAC_Job *jobs_tail; - - /** - * HTTP header "application/json", created once and used - * for all requests that need it. - */ - struct curl_slist *json_header; - -}; - - -/** - * Initialise this library. This function should be called before using any of - * the following functions. - * - * @return library context - */ -struct TALER_MINT_Context * -TALER_MINT_init () -{ - struct TALER_MINT_Context *ctx; - CURLM *multi; - CURLSH *share; - - if (TALER_MINT_curl_fail) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Curl was not initialised properly\n"); - return NULL; - } - if (NULL == (multi = curl_multi_init ())) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to create a Curl multi handle\n"); - return NULL; - } - if (NULL == (share = curl_share_init ())) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to create a Curl share handle\n"); - return NULL; - } - ctx = GNUNET_new (struct TALER_MINT_Context); - ctx->multi = multi; - ctx->share = share; - GNUNET_assert (NULL != (ctx->json_header = - curl_slist_append (NULL, - "Content-Type: application/json"))); - return ctx; -} - - -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can - * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument - * from a valid @a eh afterwards. - * - * This function modifies the CURL handle to add the - * "Content-Type: application/json" header if @a add_json is set. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will - * be executed AND cleaned up - * @param add_json add "application/json" content type header - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - */ -struct MAC_Job * -MAC_job_add (struct TALER_MINT_Context *ctx, - CURL *eh, - int add_json, - MAC_JobCompletionCallback jcc, - void *jcc_cls) -{ - struct MAC_Job *job; - - if (GNUNET_YES == add_json) - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HTTPHEADER, - ctx->json_header)); - - job = GNUNET_new (struct MAC_Job); - job->easy_handle = eh; - job->ctx = ctx; - job->jcc = jcc; - job->jcc_cls = jcc_cls; - GNUNET_CONTAINER_DLL_insert (ctx->jobs_head, - ctx->jobs_tail, - job); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_PRIVATE, - job)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_SHARE, - ctx->share)); - GNUNET_assert (CURLM_OK == - curl_multi_add_handle (ctx->multi, - eh)); - return job; -} - - -/** - * Obtain the `jcc_cls` argument from an `eh` that was - * given to #MAC_job_add(). - * - * @param eh easy handle that was used - * @return the `jcc_cls` that was given to #MAC_job_add(). - */ -void * -MAC_easy_to_closure (CURL *eh) -{ - struct MAC_Job *job; - - GNUNET_assert (CURLE_OK == - curl_easy_getinfo (eh, - CURLINFO_PRIVATE, - (char **) &job)); - return job->jcc_cls; -} - - -/** - * Cancel a job. Must only be called before the job completion - * callback is called for the respective job. - * - * @param job job to cancel - */ -void -MAC_job_cancel (struct MAC_Job *job) -{ - struct TALER_MINT_Context *ctx = job->ctx; - - GNUNET_CONTAINER_DLL_remove (ctx->jobs_head, - ctx->jobs_tail, - job); - GNUNET_assert (CURLM_OK == - curl_multi_remove_handle (ctx->multi, - job->easy_handle)); - curl_easy_cleanup (job->easy_handle); - GNUNET_free (job); -} - - -/** - * Run the main event loop for the Taler interaction. - * - * @param ctx the library context - */ -void -TALER_MINT_perform (struct TALER_MINT_Context *ctx) -{ - CURLMsg *cmsg; - struct MAC_Job *job; - int n_running; - int n_completed; - - (void) curl_multi_perform (ctx->multi, - &n_running); - while (NULL != (cmsg = curl_multi_info_read (ctx->multi, - &n_completed))) - { - /* Only documented return value is CURLMSG_DONE */ - GNUNET_break (CURLMSG_DONE == cmsg->msg); - GNUNET_assert (CURLE_OK == - curl_easy_getinfo (cmsg->easy_handle, - CURLINFO_PRIVATE, - (char **) &job)); - GNUNET_assert (job->ctx == ctx); - job->jcc (job->jcc_cls, - cmsg->easy_handle); - MAC_job_cancel (job); - } -} - - -/** - * Obtain the information for a select() call to wait until - * #TALER_MINT_perform() is ready again. Note that calling - * any other TALER_MINT-API may also imply that the library - * is again ready for #TALER_MINT_perform(). - * - * Basically, a client should use this API to prepare for select(), - * then block on select(), then call #TALER_MINT_perform() and then - * start again until the work with the context is done. - * - * This function will NOT zero out the sets and assumes that @a max_fd - * and @a timeout are already set to minimal applicable values. It is - * safe to give this API FD-sets and @a max_fd and @a timeout that are - * already initialized to some other descriptors that need to go into - * the select() call. - * - * @param ctx context to get the event loop information for - * @param read_fd_set will be set for any pending read operations - * @param write_fd_set will be set for any pending write operations - * @param except_fd_set is here because curl_multi_fdset() has this argument - * @param max_fd set to the highest FD included in any set; - * if the existing sets have no FDs in it, the initial - * value should be "-1". (Note that `max_fd + 1` will need - * to be passed to select().) - * @param timeout set to the timeout in milliseconds (!); -1 means - * no timeout (NULL, blocking forever is OK), 0 means to - * proceed immediately with #TALER_MINT_perform(). - */ -void -TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *except_fd_set, - int *max_fd, - long *timeout) -{ - long to; - int m; - - m = -1; - GNUNET_assert (CURLM_OK == - curl_multi_fdset (ctx->multi, - read_fd_set, - write_fd_set, - except_fd_set, - &m)); - to = *timeout; - *max_fd = GNUNET_MAX (m, *max_fd); - GNUNET_assert (CURLM_OK == - curl_multi_timeout (ctx->multi, - &to)); - - /* Only if what we got back from curl is smaller than what we - already had (-1 == infinity!), then update timeout */ - if ( (to < *timeout) && - (-1 != to) ) - *timeout = to; - if ( (-1 == (*timeout)) && - (NULL != ctx->jobs_head) ) - *timeout = to; -} - - -/** - * Cleanup library initialisation resources. This function should be called - * after using this library to cleanup the resources occupied during library's - * initialisation. - * - * @param ctx the library context - */ -void -TALER_MINT_fini (struct TALER_MINT_Context *ctx) -{ - /* all jobs must have been cancelled at this time, assert this */ - GNUNET_assert (NULL == ctx->jobs_head); - curl_share_cleanup (ctx->share); - curl_multi_cleanup (ctx->multi); - curl_slist_free_all (ctx->json_header); - GNUNET_free (ctx); -} - - -/** - * Callback used when downloading the reply to an HTTP request. - * Just appends all of the data to the `buf` in the - * `struct MAC_DownloadBuffer` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct KeysRequest` - * @return number of bytes processed from @a bufptr - */ -size_t -MAC_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct MAC_DownloadBuffer *db = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - db->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - db->buf = GNUNET_realloc (db->buf, - db->buf_size + msize); - buf = db->buf + db->buf_size; - memcpy (buf, bufptr, msize); - db->buf_size += msize; - return msize; -} - - -/** - * Obtain information about the final result about the - * HTTP download. If the download was successful, parses - * the JSON in the @a db and returns it. Also returns - * the HTTP @a response_code. If the download failed, - * the return value is NULL. The response code is set - * in any case, on download errors to zero. - * - * Calling this function also cleans up @a db. - * - * @param db download buffer - * @param eh CURL handle (to get the response code) - * @param[out] response_code set to the HTTP response code - * (or zero if we aborted the download, i.e. - * because the response was too big, or if - * the JSON we received was malformed). - * @return NULL if downloading a JSON reply failed - */ -json_t * -MAC_download_get_result (struct MAC_DownloadBuffer *db, - CURL *eh, - long *response_code) -{ - json_t *json; - json_error_t error; - char *ct; - - if ( (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_CONTENT_TYPE, - &ct)) || - (NULL == ct) || - (0 != strcasecmp (ct, - "application/json")) ) - { - /* No content type or explicitly not JSON, refuse to parse - (but keep response code) */ - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - *response_code = 0; - } - return NULL; - } - - json = NULL; - if (0 == db->eno) - { - json = json_loadb (db->buf, - db->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == json) - { - JSON_WARN (error); - *response_code = 0; - } - } - GNUNET_free_non_null (db->buf); - db->buf = NULL; - db->buf_size = 0; - if (NULL != json) - { - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - *response_code = 0; - } - } - return json; -} - - -/** - * Initial global setup logic, specifically runs the Curl setup. - */ -__attribute__ ((constructor)) -void -TALER_MINT_constructor__ (void) -{ - CURLcode ret; - - if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT))) - { - CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, - "curl_global_init", - ret); - TALER_MINT_curl_fail = 1; - } -} - - -/** - * Cleans up after us, specifically runs the Curl cleanup. - */ -__attribute__ ((destructor)) -void -TALER_MINT_destructor__ (void) -{ - if (TALER_MINT_curl_fail) - return; - curl_global_cleanup (); -} - -/* end of mint_api_context.c */ diff --git a/src/mint-lib/mint_api_context.h b/src/mint-lib/mint_api_context.h deleted file mode 100644 index 181a4808f..000000000 --- a/src/mint-lib/mint_api_context.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_context.h - * @brief Internal interface to the context part of the mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "taler_signatures.h" - - -/** - * Entry in the context's job queue. - */ -struct MAC_Job; - -/** - * Function to call upon completion of a job. - * - * @param cls closure - * @param eh original easy handle (for inspection) - */ -typedef void -(*MAC_JobCompletionCallback)(void *cls, - CURL *eh); - - -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. Applications can - * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument - * from a valid @a eh afterwards. - * - * This function modifies the CURL handle to add the - * "Content-Type: application/json" header if @a add_json is set. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will - * be executed AND cleaned up - * @param add_json add "application/json" content type header - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - */ -struct MAC_Job * -MAC_job_add (struct TALER_MINT_Context *ctx, - CURL *eh, - int add_json, - MAC_JobCompletionCallback jcc, - void *jcc_cls); - - -/** - * Obtain the `jcc_cls` argument from an `eh` that was - * given to #MAC_job_add(). - * - * @param eh easy handle that was used - * @return the `jcc_cls` that was given to #MAC_job_add(). - */ -void * -MAC_easy_to_closure (CURL *eh); - - -/** - * Cancel a job. Must only be called before the job completion - * callback is called for the respective job. - * - * @param job job to cancel - */ -void -MAC_job_cancel (struct MAC_Job *job); - - -/** - * @brief Buffer data structure we use to buffer the HTTP download - * before giving it to the JSON parser. - */ -struct MAC_DownloadBuffer -{ - - /** - * Download buffer - */ - void *buf; - - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; - -}; - - -/** - * Callback used when downloading the reply to an HTTP request. - * Just appends all of the data to the `buf` in the - * `struct MAC_DownloadBuffer` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * Should be used by the various routines as the - * CURLOPT_WRITEFUNCTION. A `struct MAC_DownloadBuffer` needs to be - * passed to the CURLOPT_WRITEDATA. - * - * Afterwards, `eno` needs to be checked to ensure that the download - * completed correctly. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct KeysRequest` - * @return number of bytes processed from @a bufptr - */ -size_t -MAC_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls); - - -/** - * Obtain information about the final result about the - * HTTP download. If the download was successful, parses - * the JSON in the @a db and returns it. Also returns - * the HTTP @a response_code. If the download failed, - * the return value is NULL. The response code is set - * in any case, on download errors to zero. - * - * Calling this function also cleans up @a db. - * - * @param db download buffer - * @param eh CURL handle (to get the response code) - * @param[out] response_code set to the HTTP response code - * (or zero if we aborted the download, i.e. - * because the response was too big, or if - * the JSON we received was malformed). - * @return NULL if downloading a JSON reply failed - */ -json_t * -MAC_download_get_result (struct MAC_DownloadBuffer *db, - CURL *eh, - long *response_code); - - -/* end of mint_api_context.h */ diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c deleted file mode 100644 index 400372925..000000000 --- a/src/mint-lib/mint_api_deposit.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_deposit.c - * @brief Implementation of the /deposit request of the mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A Deposit Handle - */ -struct TALER_MINT_DepositHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_DepositResultCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Information the mint should sign in response. - */ - struct TALER_DepositConfirmationPS depconf; - - /** - * Value of the /deposit transaction, including fee. - */ - struct TALER_Amount amount_with_fee; - - /** - * Total value of the coin being transacted with. - */ - struct TALER_Amount coin_value; - -}; - - -/** - * Verify that the signature on the "200 OK" response - * from the mint is valid. - * - * @param dh deposit handle - * @param json json reply with the signature - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static int -verify_deposit_signature_ok (const struct TALER_MINT_DepositHandle *dh, - json_t *json) -{ - struct TALER_MintSignatureP mint_sig; - struct TALER_MintPublicKeyP mint_pub; - const struct TALER_MINT_Keys *key_state; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("sig", &mint_sig), - MAJ_spec_fixed_auto ("pub", &mint_pub), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - key_state = TALER_MINT_get_keys (dh->mint); - if (GNUNET_OK != - TALER_MINT_test_signing_key (key_state, - &mint_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT, - &dh->depconf.purpose, - &mint_sig.eddsa_signature, - &mint_pub.eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Verify that the signatures on the "403 FORBIDDEN" response from the - * mint demonstrating customer double-spending are valid. - * - * @param dh deposit handle - * @param json json reply with the signature(s) and transaction history - * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not - */ -static int -verify_deposit_signature_forbidden (const struct TALER_MINT_DepositHandle *dh, - json_t *json) -{ - json_t *history; - struct TALER_Amount total; - - history = json_object_get (json, - "history"); - if (GNUNET_OK != - TALER_MINT_verify_coin_history_ (dh->coin_value.currency, - &dh->depconf.coin_pub, - history, - &total)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_amount_add (&total, - &total, - &dh->amount_with_fee)) - { - /* clearly not OK if our transaction would have caused - the overflow... */ - return GNUNET_OK; - } - - if (0 >= TALER_amount_cmp (&total, - &dh->coin_value)) - { - /* transaction should have still fit */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* everything OK, proof of double-spending was provided */ - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /deposit request. - * - * @param cls the `struct TALER_MINT_DepositHandle` - * @param eh the curl request handle - */ -static void -handle_deposit_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_DepositHandle *dh = cls; - long response_code; - json_t *json; - - dh->job = NULL; - json = MAC_download_get_result (&dh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - verify_deposit_signature_ok (dh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_FORBIDDEN: - /* Double spending; check signatures on transaction history */ - if (GNUNET_OK != - verify_deposit_signature_forbidden (dh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - dh->cb (dh->cb_cls, - response_code, - json); - json_decref (json); - TALER_MINT_deposit_cancel (dh); -} - - -/** - * Verify signature information about the deposit. - * - * @param dki public key information - * @param amount the amount to be deposited - * @param h_wire hash of the merchant’s account details - * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) - * @param coin_pub coin’s public key - * @param denom_pub denomination key with which the coin is signed - * @param denom_sig mint’s unblinded signature of the coin - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed) - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not - */ -static int -verify_signatures (const struct TALER_MINT_DenomPublicKey *dki, - const struct TALER_Amount *amount, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationSignature *denom_sig, - const struct TALER_DenominationPublicKey *denom_pub, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_CoinSpendSignatureP *coin_sig) -{ - struct TALER_DepositRequestPS dr; - struct TALER_CoinPublicInfo coin_info; - - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = *h_contract; - dr.h_wire = *h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - dr.transaction_id = GNUNET_htonll (transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - amount); - TALER_amount_hton (&dr.deposit_fee, - &dki->fee_deposit); - dr.merchant = *merchant_pub; - dr.coin_pub = *coin_pub; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &coin_sig->eddsa_signature, - &coin_pub->eddsa_pub)) - { - TALER_LOG_WARNING ("Invalid coin signature on /deposit request\n"); - { - char *s; - s = TALER_amount_to_string (amount); - TALER_LOG_DEBUG ("... amount_with_fee was %s\n", s); - GNUNET_free (s); - s = TALER_amount_to_string (&dki->fee_deposit); - TALER_LOG_DEBUG ("... deposit_fee was %s\n", s); - GNUNET_free (s); - } - - return GNUNET_SYSERR; - } - - /* check coin signature */ - coin_info.coin_pub = *coin_pub; - coin_info.denom_pub = *denom_pub; - coin_info.denom_sig = *denom_sig; - if (GNUNET_YES != - TALER_test_coin_valid (&coin_info)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - return GNUNET_SYSERR; - } - if (0 < TALER_amount_cmp (&dki->fee_deposit, - amount)) - { - TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Submit a deposit permission to the mint and get the mint's response. - * Note that while we return the response verbatim to the caller for - * further processing, we do already verify that the response is - * well-formed (i.e. that signatures included in the response are all - * valid). If the mint's reply is not well-formed, we return an - * HTTP status code of zero to @a cb. - * - * We also verify that the @a coin_sig is valid for this deposit - * request, and that the @a ub_sig is a valid signature for @a - * coin_pub. Also, the @a mint must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the transaction with the mint and instead return NULL. - * - * @param mint the mint handle; the mint must be ready to operate - * @param amount the amount to be deposited - * @param wire_deadline date until which the merchant would like the mint to settle the balance (advisory, the mint cannot be - * forced to settle in the past or upon very short notice, but of course a well-behaved mint will limit aggregation based on the advice received) - * @param wire_details the merchant’s account details, in a format supported by the mint - * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) - * @param coin_pub coin’s public key - * @param denom_pub denomination key with which the coin is signed - * @param denom_sig mint’s unblinded signature of the coin - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed) - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_MINT_DepositHandle * -TALER_MINT_deposit (struct TALER_MINT_Handle *mint, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute wire_deadline, - json_t *wire_details, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationSignature *denom_sig, - const struct TALER_DenominationPublicKey *denom_pub, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_CoinSpendSignatureP *coin_sig, - TALER_MINT_DepositResultCallback cb, - void *cb_cls) -{ - const struct TALER_MINT_Keys *key_state; - const struct TALER_MINT_DenomPublicKey *dki; - struct TALER_MINT_DepositHandle *dh; - struct TALER_MINT_Context *ctx; - json_t *deposit_obj; - CURL *eh; - struct GNUNET_HashCode h_wire; - struct TALER_Amount amount_without_fee; - - (void) TALER_round_abs_time (&wire_deadline); - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - /* initialize h_wire */ - if (GNUNET_OK != - TALER_hash_json (wire_details, - &h_wire)) - { - GNUNET_break (0); - return NULL; - } - key_state = TALER_MINT_get_keys (mint); - dki = TALER_MINT_get_denomination_key (key_state, - denom_pub); - if (NULL == dki) - { - TALER_LOG_WARNING ("Denomination key unknown to mint\n"); - return NULL; - } - if (GNUNET_SYSERR == - TALER_amount_subtract (&amount_without_fee, - amount, - &dki->fee_deposit)) - { - GNUNET_break (0); - return NULL; - } - - if (GNUNET_OK != - verify_signatures (dki, - amount, - &h_wire, - h_contract, - coin_pub, - denom_sig, - denom_pub, - timestamp, - transaction_id, - merchant_pub, - refund_deadline, - coin_sig)) - { - GNUNET_break_op (0); - return NULL; - } - - deposit_obj = json_pack ("{s:o, s:O," /* f/wire */ - " s:o, s:o," /* H_wire, H_contract */ - " s:o, s:o," /* coin_pub, denom_pub */ - " s:o, s:o," /* ub_sig, timestamp */ - " s:I, s:o," /* transaction id, merchant_pub */ - " s:o, s:o," /* refund_deadline, wire_deadline */ - " s:o}", /* coin_sig */ - "f", TALER_json_from_amount (amount), - "wire", wire_details, - "H_wire", TALER_json_from_data (&h_wire, - sizeof (h_wire)), - "H_contract", TALER_json_from_data (h_contract, - sizeof (struct GNUNET_HashCode)), - "coin_pub", TALER_json_from_data (coin_pub, - sizeof (*coin_pub)), - "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key), - "ub_sig", TALER_json_from_rsa_signature (denom_sig->rsa_signature), - "timestamp", TALER_json_from_abs (timestamp), - "transaction_id", (json_int_t) transaction_id, - "merchant_pub", TALER_json_from_data (merchant_pub, - sizeof (*merchant_pub)), - "refund_deadline", TALER_json_from_abs (refund_deadline), - "edate", TALER_json_from_abs (wire_deadline), - "coin_sig", TALER_json_from_data (coin_sig, - sizeof (*coin_sig)) - ); - - dh = GNUNET_new (struct TALER_MINT_DepositHandle); - dh->mint = mint; - dh->cb = cb; - dh->cb_cls = cb_cls; - dh->url = MAH_path_to_url (mint, "/deposit"); - dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); - dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT); - dh->depconf.h_contract = *h_contract; - dh->depconf.h_wire = h_wire; - dh->depconf.transaction_id = GNUNET_htonll (transaction_id); - dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - TALER_amount_hton (&dh->depconf.amount_without_fee, - &amount_without_fee); - dh->depconf.coin_pub = *coin_pub; - dh->depconf.merchant = *merchant_pub; - dh->amount_with_fee = *amount; - dh->coin_value = dki->value; - - eh = curl_easy_init (); - GNUNET_assert (NULL != (dh->json_enc = - json_dumps (deposit_obj, - JSON_COMPACT))); - json_decref (deposit_obj); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "URL for deposit: `%s'\n", - dh->url); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - dh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - dh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (dh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &dh->db)); - ctx = MAH_handle_to_context (mint); - dh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_deposit_finished, - dh); - return dh; -} - - -/** - * Cancel a deposit permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit the deposit permission request handle - */ -void -TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit) -{ - if (NULL != deposit->job) - { - MAC_job_cancel (deposit->job); - deposit->job = NULL; - } - GNUNET_free_non_null (deposit->db.buf); - GNUNET_free (deposit->url); - GNUNET_free (deposit->json_enc); - GNUNET_free (deposit); -} - - -/* end of mint_api_deposit.c */ diff --git a/src/mint-lib/mint_api_deposit_wtid.c b/src/mint-lib/mint_api_deposit_wtid.c deleted file mode 100644 index d29f406e3..000000000 --- a/src/mint-lib/mint_api_deposit_wtid.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_deposit_wtid.c - * @brief Implementation of the /deposit/wtid request of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A Deposit Wtid Handle - */ -struct TALER_MINT_DepositWtidHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_DepositWtidCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Information the mint should sign in response. - * (with pre-filled fields from the request). - */ - struct TALER_ConfirmWirePS depconf; - -}; - - -/** - * Verify that the signature on the "200 OK" response - * from the mint is valid. - * - * @param dwh deposit wtid handle - * @param json json reply with the signature - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static int -verify_deposit_wtid_signature_ok (const struct TALER_MINT_DepositWtidHandle *dwh, - json_t *json) -{ - struct TALER_MintSignatureP mint_sig; - struct TALER_MintPublicKeyP mint_pub; - const struct TALER_MINT_Keys *key_state; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("mint_sig", &mint_sig), - MAJ_spec_fixed_auto ("mint_pub", &mint_pub), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - key_state = TALER_MINT_get_keys (dwh->mint); - if (GNUNET_OK != - TALER_MINT_test_signing_key (key_state, - &mint_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_WIRE, - &dwh->depconf.purpose, - &mint_sig.eddsa_signature, - &mint_pub.eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /deposit/wtid request. - * - * @param cls the `struct TALER_MINT_DepositWtidHandle` - * @param eh the curl request handle - */ -static void -handle_deposit_wtid_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_DepositWtidHandle *dwh = cls; - long response_code; - json_t *json; - const struct TALER_WireTransferIdentifierRawP *wtid = NULL; - struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS; - const struct TALER_Amount *coin_contribution = NULL; - struct TALER_Amount coin_contribution_s; - - dwh->job = NULL; - json = MAC_download_get_result (&dwh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid), - MAJ_spec_absolute_time ("execution_time", &execution_time), - MAJ_spec_amount ("coin_contribution", &coin_contribution_s), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - wtid = &dwh->depconf.wtid; - dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time); - TALER_amount_hton (&dwh->depconf.coin_contribution, - &coin_contribution_s); - coin_contribution = &coin_contribution_s; - if (GNUNET_OK != - verify_deposit_wtid_signature_ok (dwh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - } - break; - case MHD_HTTP_ACCEPTED: - { - /* Transaction known, but not executed yet */ - struct MAJ_Specification spec[] = { - MAJ_spec_absolute_time ("execution_time", &execution_time), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Mint does not know about transaction; - we should pass the reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - dwh->cb (dwh->cb_cls, - response_code, - json, - wtid, - execution_time, - coin_contribution); - json_decref (json); - TALER_MINT_deposit_wtid_cancel (dwh); -} - - -/** - * Obtain wire transfer details about an existing deposit operation. - * - * @param mint the mint to query - * @param merchant_priv the merchant's private key - * @param h_wire hash of merchant's wire transfer details - * @param h_contract hash of the contract - * @param coin_pub public key of the coin - * @param transaction_id transaction identifier - * @param cb function to call with the result - * @param cb_cls closure for @a cb - * @return handle to abort request - */ -struct TALER_MINT_DepositWtidHandle * -TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint, - const struct TALER_MerchantPrivateKeyP *merchant_priv, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - uint64_t transaction_id, - TALER_MINT_DepositWtidCallback cb, - void *cb_cls) -{ - struct TALER_DepositTrackPS dtp; - struct TALER_MerchantSignatureP merchant_sig; - struct TALER_MINT_DepositWtidHandle *dwh; - struct TALER_MINT_Context *ctx; - json_t *deposit_wtid_obj; - CURL *eh; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID); - dtp.purpose.size = htonl (sizeof (dtp)); - dtp.h_contract = *h_contract; - dtp.h_wire = *h_wire; - dtp.transaction_id = GNUNET_htonll (transaction_id); - GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv, - &dtp.merchant.eddsa_pub); - - dtp.coin_pub = *coin_pub; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, - &dtp.purpose, - &merchant_sig.eddsa_sig)); - deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */ - " s:o, s:I," /* coin_pub, transaction_id */ - " s:o, s:o}", /* merchant_pub, merchant_sig */ - "H_wire", TALER_json_from_data (h_wire, - sizeof (struct GNUNET_HashCode)), - "H_contract", TALER_json_from_data (h_contract, - sizeof (struct GNUNET_HashCode)), - "coin_pub", TALER_json_from_data (coin_pub, - sizeof (*coin_pub)), - "transaction_id", (json_int_t) transaction_id, - "merchant_pub", TALER_json_from_data (&dtp.merchant, - sizeof (struct TALER_MerchantPublicKeyP)), - "merchant_sig", TALER_json_from_data (&merchant_sig, - sizeof (merchant_sig))); - - dwh = GNUNET_new (struct TALER_MINT_DepositWtidHandle); - dwh->mint = mint; - dwh->cb = cb; - dwh->cb_cls = cb_cls; - dwh->url = MAH_path_to_url (mint, "/deposit/wtid"); - dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); - dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE); - dwh->depconf.h_wire = *h_wire; - dwh->depconf.h_contract = *h_contract; - dwh->depconf.coin_pub = *coin_pub; - dwh->depconf.transaction_id = GNUNET_htonll (transaction_id); - - eh = curl_easy_init (); - GNUNET_assert (NULL != (dwh->json_enc = - json_dumps (deposit_wtid_obj, - JSON_COMPACT))); - json_decref (deposit_wtid_obj); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - dwh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - dwh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (dwh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &dwh->db)); - ctx = MAH_handle_to_context (mint); - dwh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_deposit_wtid_finished, - dwh); - return dwh; -} - - -/** - * Cancel deposit wtid request. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param dwh the wire deposits request handle - */ -void -TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh) -{ - if (NULL != dwh->job) - { - MAC_job_cancel (dwh->job); - dwh->job = NULL; - } - GNUNET_free_non_null (dwh->db.buf); - GNUNET_free (dwh->url); - GNUNET_free (dwh->json_enc); - GNUNET_free (dwh); -} - - -/* end of mint_api_deposit_wtid.c */ diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c deleted file mode 100644 index ef26cd838..000000000 --- a/src/mint-lib/mint_api_handle.c +++ /dev/null @@ -1,902 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_handle.c - * @brief Implementation of the "handle" component of the mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler_mint_service.h" -#include "taler_signatures.h" -#include "mint_api_context.h" -#include "mint_api_json.h" -#include "mint_api_handle.h" - - -/** - * Log error related to CURL operations. - * - * @param type log level - * @param function which function failed to run - * @param code what was the curl error code - */ -#define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ - function, __FILE__, __LINE__, curl_easy_strerror (code)); - - -/** - * Stages of initialization for the `struct TALER_MINT_Handle` - */ -enum MintHandleState -{ - /** - * Just allocated. - */ - MHS_INIT = 0, - - /** - * Obtained the mint's certification data and keys. - */ - MHS_CERT = 1, - - /** - * Failed to initialize (fatal). - */ - MHS_FAILED = 2 -}; - - -/** - * Data for the request to get the /keys of a mint. - */ -struct KeysRequest; - - -/** - * Handle to the mint - */ -struct TALER_MINT_Handle -{ - /** - * The context of this handle - */ - struct TALER_MINT_Context *ctx; - - /** - * The URL of the mint (i.e. "http://mint.taler.net/") - */ - char *url; - - /** - * Function to call with the mint's certification data, - * NULL if this has already been done. - */ - TALER_MINT_CertificationCallback cert_cb; - - /** - * Closure to pass to @e cert_cb. - */ - void *cert_cb_cls; - - /** - * Data for the request to get the /keys of a mint, - * NULL once we are past stage #MHS_INIT. - */ - struct KeysRequest *kr; - - /** - * Key data of the mint, only valid if - * @e handshake_complete is past stage #MHS_CERT. - */ - struct TALER_MINT_Keys key_data; - - /** - * Stage of the mint's initialization routines. - */ - enum MintHandleState state; - -}; - - -/* ***************** Internal /keys fetching ************* */ - -/** - * Data for the request to get the /keys of a mint. - */ -struct KeysRequest -{ - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this handle - */ - char *url; - - /** - * Entry for this request with the `struct TALER_MINT_Context`. - */ - struct MAC_Job *job; - - /** - * Data structure for the download. - */ - struct MAC_DownloadBuffer db; - -}; - - -/** - * Release memory occupied by a keys request. - * Note that this does not cancel the request - * itself. - * - * @param kr request to free - */ -static void -free_keys_request (struct KeysRequest *kr) -{ - GNUNET_free_non_null (kr->db.buf); - GNUNET_free (kr->url); - GNUNET_free (kr); -} - - -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Parse a mint's signing key encoded in JSON. - * - * @param[out] sign_key where to return the result - * @param[in] sign_key_obj json to parse - * @param master_key master key to use to verify signature - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_signkey (struct TALER_MINT_SigningPublicKey *sign_key, - json_t *sign_key_obj, - const struct TALER_MasterPublicKeyP *master_key) -{ - struct TALER_MintSigningKeyValidityPS sign_key_issue; - struct GNUNET_CRYPTO_EddsaSignature sig; - struct GNUNET_TIME_Absolute valid_from; - struct GNUNET_TIME_Absolute valid_until; - struct GNUNET_TIME_Absolute valid_legal; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("master_sig", - &sig), - MAJ_spec_fixed_auto ("key", - &sign_key_issue.signkey_pub), - MAJ_spec_absolute_time ("stamp_start", - &valid_from), - MAJ_spec_absolute_time ("stamp_expire", - &valid_until), - MAJ_spec_absolute_time ("stamp_end", - &valid_legal), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (sign_key_obj, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); - sign_key_issue.purpose.size = - htonl (sizeof (struct TALER_MintSigningKeyValidityPS) - - offsetof (struct TALER_MintSigningKeyValidityPS, - purpose)); - sign_key_issue.master_public_key = *master_key; - sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); - sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until); - sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, - &sign_key_issue.purpose, - &sig, - &master_key->eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - sign_key->valid_from = valid_from; - sign_key->valid_until = valid_until; - sign_key->key = sign_key_issue.signkey_pub; - return GNUNET_OK; -} - - -/** - * Parse a mint's denomination key encoded in JSON. - * - * @param[out] denom_key where to return the result - * @param[in] denom_key_obj json to parse - * @param master_key master key to use to verify signature - * @param hash_context where to accumulate data for signature verification - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key, - json_t *denom_key_obj, - struct TALER_MasterPublicKeyP *master_key, - struct GNUNET_HashContext *hash_context) -{ - struct GNUNET_TIME_Absolute valid_from; - struct GNUNET_TIME_Absolute withdraw_valid_until; - struct GNUNET_TIME_Absolute deposit_valid_until; - struct GNUNET_TIME_Absolute expire_legal; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_deposit; - struct TALER_Amount fee_refresh; - struct TALER_DenominationKeyValidityPS denom_key_issue; - struct GNUNET_CRYPTO_rsa_PublicKey *pk; - struct GNUNET_CRYPTO_EddsaSignature sig; - - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("master_sig", - &sig), - MAJ_spec_absolute_time ("stamp_expire_deposit", - &deposit_valid_until), - MAJ_spec_absolute_time ("stamp_expire_withdraw", - &withdraw_valid_until), - MAJ_spec_absolute_time ("stamp_start", - &valid_from), - MAJ_spec_absolute_time ("stamp_expire_legal", - &expire_legal), - MAJ_spec_amount ("value", - &value), - MAJ_spec_amount ("fee_withdraw", - &fee_withdraw), - MAJ_spec_amount ("fee_deposit", - &fee_deposit), - MAJ_spec_amount ("fee_refresh", - &fee_refresh), - MAJ_spec_rsa_public_key ("denom_pub", - &pk), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (denom_key_obj, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - memset (&denom_key_issue, 0, sizeof (denom_key_issue)); - GNUNET_CRYPTO_rsa_public_key_hash (pk, - &denom_key_issue.denom_hash); - denom_key_issue.purpose.purpose - = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); - denom_key_issue.purpose.size - = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); - denom_key_issue.master = *master_key; - denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from); - denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until); - denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until); - denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal); - TALER_amount_hton (&denom_key_issue.value, - &value); - TALER_amount_hton (&denom_key_issue.fee_withdraw, - &fee_withdraw); - TALER_amount_hton (&denom_key_issue.fee_deposit, - &fee_deposit); - TALER_amount_hton (&denom_key_issue.fee_refresh, - &fee_refresh); - EXITIF (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, - &denom_key_issue.purpose, - &sig, - &master_key->eddsa_pub)); - GNUNET_CRYPTO_hash_context_read (hash_context, - &denom_key_issue.denom_hash, - sizeof (struct GNUNET_HashCode)); - denom_key->key.rsa_public_key = pk; - denom_key->h_key = denom_key_issue.denom_hash; - denom_key->valid_from = valid_from; - denom_key->withdraw_valid_until = withdraw_valid_until; - denom_key->deposit_valid_until = deposit_valid_until; - denom_key->expire_legal = expire_legal; - denom_key->value = value; - denom_key->fee_withdraw = fee_withdraw; - denom_key->fee_deposit = fee_deposit; - denom_key->fee_refresh = fee_refresh; - return GNUNET_OK; - - EXITIF_exit: - MAJ_parse_free (spec); - return GNUNET_SYSERR; -} - - -/** - * Parse a mint's auditor information encoded in JSON. - * - * @param[out] auditor where to return the result - * @param[in] auditor_obj json to parse - * @param key_data information about denomination keys - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_auditor (struct TALER_MINT_AuditorInformation *auditor, - json_t *auditor_obj, - const struct TALER_MINT_Keys *key_data) -{ - json_t *keys; - json_t *key; - unsigned int len; - unsigned int off; - unsigned int i; - struct TALER_MintKeyValidityPS kv; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("auditor_pub", - &auditor->auditor_pub), - MAJ_spec_json ("denomination_keys", - &keys), - MAJ_spec_end - }; - - auditor->auditor_url = NULL; /* #3987 */ - if (GNUNET_OK != - MAJ_parse_json (auditor_obj, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_MINT_KEYS); - kv.purpose.size = htonl (sizeof (struct TALER_MintKeyValidityPS)); - kv.master = key_data->master_pub; - len = json_array_size (keys); - auditor->denom_keys = GNUNET_new_array (len, - const struct TALER_MINT_DenomPublicKey *); - i = 0; - off = 0; - json_array_foreach (keys, i, key) { - struct TALER_AuditorSignatureP auditor_sig; - struct GNUNET_HashCode denom_h; - const struct TALER_MINT_DenomPublicKey *dk; - unsigned int j; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("denom_pub_h", - &denom_h), - MAJ_spec_fixed_auto ("auditor_sig", - &auditor_sig), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (key, - spec)) - { - GNUNET_break_op (0); - continue; - } - dk = NULL; - for (j=0;j<key_data->num_denom_keys;j++) - { - if (0 == memcmp (&denom_h, - &key_data->denom_keys[j].h_key, - sizeof (struct GNUNET_HashCode))) - { - dk = &key_data->denom_keys[j]; - break; - } - } - if (NULL == dk) - { - GNUNET_break_op (0); - continue; - } - kv.start = GNUNET_TIME_absolute_hton (dk->valid_from); - kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until); - kv.expire_spend = GNUNET_TIME_absolute_hton (dk->deposit_valid_until); - kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal); - TALER_amount_hton (&kv.value, - &dk->value); - TALER_amount_hton (&kv.fee_withdraw, - &dk->fee_withdraw); - TALER_amount_hton (&kv.fee_deposit, - &dk->fee_deposit); - TALER_amount_hton (&kv.fee_refresh, - &dk->fee_refresh); - kv.denom_hash = dk->h_key; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_MINT_KEYS, - &kv.purpose, - &auditor_sig.eddsa_sig, - &auditor->auditor_pub.eddsa_pub)) - { - GNUNET_break_op (0); - continue; - } - auditor->denom_keys[off] = dk; - off++; - } - auditor->num_denom_keys = off; - return GNUNET_OK; -} - - -/** - * Decode the JSON in @a resp_obj from the /keys response and store the data - * in the @a key_data. - * - * @param[in] resp_obj JSON object to parse - * @param[out] key_data where to store the results we decoded - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON) - */ -static int -decode_keys_json (json_t *resp_obj, - struct TALER_MINT_Keys *key_data) -{ - struct GNUNET_TIME_Absolute list_issue_date; - struct TALER_MintSignatureP sig; - struct TALER_MintKeySetPS ks; - struct GNUNET_HashContext *hash_context; - struct TALER_MintPublicKeyP pub; - - if (JSON_OBJECT != json_typeof (resp_obj)) - return GNUNET_SYSERR; - - hash_context = GNUNET_CRYPTO_hash_context_start (); - /* parse the master public key and issue date of the response */ - { - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("master_public_key", - &key_data->master_pub), - MAJ_spec_fixed_auto ("eddsa_sig", - &sig), - MAJ_spec_fixed_auto ("eddsa_pub", - &pub), - MAJ_spec_absolute_time ("list_issue_date", - &list_issue_date), - MAJ_spec_end - }; - - EXITIF (GNUNET_OK != - MAJ_parse_json (resp_obj, - spec)); - } - - /* parse the signing keys */ - { - json_t *sign_keys_array; - json_t *sign_key_obj; - unsigned int index; - - EXITIF (NULL == (sign_keys_array = - json_object_get (resp_obj, - "signkeys"))); - EXITIF (JSON_ARRAY != json_typeof (sign_keys_array)); - EXITIF (0 == (key_data->num_sign_keys = - json_array_size (sign_keys_array))); - key_data->sign_keys - = GNUNET_new_array (key_data->num_sign_keys, - struct TALER_MINT_SigningPublicKey); - index = 0; - json_array_foreach (sign_keys_array, index, sign_key_obj) { - EXITIF (GNUNET_SYSERR == - parse_json_signkey (&key_data->sign_keys[index], - sign_key_obj, - &key_data->master_pub)); - } - } - - /* parse the denomination keys */ - { - json_t *denom_keys_array; - json_t *denom_key_obj; - unsigned int index; - - EXITIF (NULL == (denom_keys_array = - json_object_get (resp_obj, "denoms"))); - EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); - EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array))); - key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys, - struct TALER_MINT_DenomPublicKey); - index = 0; - json_array_foreach (denom_keys_array, index, denom_key_obj) { - EXITIF (GNUNET_SYSERR == - parse_json_denomkey (&key_data->denom_keys[index], - denom_key_obj, - &key_data->master_pub, - hash_context)); - } - } - - /* parse the auditor information */ - { - json_t *auditors_array; - json_t *auditor_info; - unsigned int len; - unsigned int index; - - EXITIF (NULL == (auditors_array = - json_object_get (resp_obj, "auditors"))); - EXITIF (JSON_ARRAY != json_typeof (auditors_array)); - len = json_array_size (auditors_array); - if (0 != len) - { - key_data->auditors = GNUNET_new_array (len, - struct TALER_MINT_AuditorInformation); - index = 0; - json_array_foreach (auditors_array, index, auditor_info) { - EXITIF (GNUNET_SYSERR == - parse_json_auditor (&key_data->auditors[index], - auditor_info, - key_data)); - } - } - } - - /* Validate signature... */ - ks.purpose.size = htonl (sizeof (ks)); - ks.purpose.purpose = htonl (TALER_SIGNATURE_MINT_KEY_SET); - ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date); - GNUNET_CRYPTO_hash_context_finish (hash_context, - &ks.hc); - hash_context = NULL; - EXITIF (GNUNET_OK != - TALER_MINT_test_signing_key (key_data, - &pub)); - EXITIF (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_KEY_SET, - &ks.purpose, - &sig.eddsa_signature, - &pub.eddsa_pub)); - return GNUNET_OK; - EXITIF_exit: - - if (NULL != hash_context) - GNUNET_CRYPTO_hash_context_abort (hash_context); - return GNUNET_SYSERR; -} - - -/** - * Callback used when downloading the reply to a /keys request - * is complete. - * - * @param cls the `struct KeysRequest` - * @param eh easy handle of the original request - */ -static void -keys_completed_cb (void *cls, - CURL *eh) -{ - struct KeysRequest *kr = cls; - struct TALER_MINT_Handle *mint = kr->mint; - json_t *resp_obj; - long response_code; - TALER_MINT_CertificationCallback cb; - - resp_obj = MAC_download_get_result (&kr->db, - eh, - &response_code); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received keys from URL `%s' with status %ld.\n", - kr->url, - response_code); - switch (response_code) { - case 0: - break; - case MHD_HTTP_OK: - if ( (NULL == resp_obj) || - (GNUNET_OK != - decode_keys_json (resp_obj, - &kr->mint->key_data)) ) - response_code = 0; - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - break; - } - if (NULL != resp_obj) - json_decref (resp_obj); - - if (MHD_HTTP_OK != response_code) - { - mint->kr = NULL; - free_keys_request (kr); - mint->state = MHS_FAILED; - /* notify application that we failed */ - if (NULL != (cb = mint->cert_cb)) - { - mint->cert_cb = NULL; - cb (mint->cert_cb_cls, - NULL); - } - return; - } - mint->kr = NULL; - free_keys_request (kr); - mint->state = MHS_CERT; - /* notify application about the key information */ - if (NULL != (cb = mint->cert_cb)) - { - mint->cert_cb = NULL; - cb (mint->cert_cb_cls, - &mint->key_data); - } -} - - -/* ********************* library internal API ********* */ - - -/** - * Get the context of a mint. - * - * @param h the mint handle to query - * @return ctx context to execute jobs in - */ -struct TALER_MINT_Context * -MAH_handle_to_context (struct TALER_MINT_Handle *h) -{ - return h->ctx; -} - - -/** - * Check if the handle is ready to process requests. - * - * @param h the mint handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -int -MAH_handle_is_ready (struct TALER_MINT_Handle *h) -{ - return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO; -} - - -/** - * Obtain the URL to use for an API request. - * - * @param h the mint handle to query - * @param path Taler API path (i.e. "/reserve/withdraw") - * @return the full URI to use with cURL - */ -char * -MAH_path_to_url (struct TALER_MINT_Handle *h, - const char *path) -{ - char *url; - - if ( ('/' == path[0]) && - (0 < strlen (h->url)) && - ('/' == h->url[strlen (h->url) - 1]) ) - path++; /* avoid generating URL with "//" from concat */ - GNUNET_asprintf (&url, - "%s%s", - h->url, - path); - return url; -} - - -/* ********************* public API ******************* */ - -/** - * Initialise a connection to the mint. Will connect to the - * mint and obtain information about the mint's master public - * key and the mint's auditor. The respective information will - * be passed to the @a cert_cb once available, and all future - * interactions with the mint will be checked to be signed - * (where appropriate) by the respective master key. - * - * @param ctx the context - * @param url HTTP base URL for the mint - * @param cert_cb function to call with the mint's certification information - * @param cert_cb_cls closure for @a cert_cb - * @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END. - * @return the mint handle; NULL upon error - */ -struct TALER_MINT_Handle * -TALER_MINT_connect (struct TALER_MINT_Context *ctx, - const char *url, - TALER_MINT_CertificationCallback cert_cb, - void *cert_cb_cls, - ...) -{ - struct TALER_MINT_Handle *mint; - struct KeysRequest *kr; - CURL *c; - - mint = GNUNET_new (struct TALER_MINT_Handle); - mint->ctx = ctx; - mint->url = GNUNET_strdup (url); - mint->cert_cb = cert_cb; - mint->cert_cb_cls = cert_cb_cls; - kr = GNUNET_new (struct KeysRequest); - kr->mint = mint; - kr->url = MAH_path_to_url (mint, "/keys"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting keys with URL `%s'.\n", - kr->url); - c = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_VERBOSE, - 0)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_STDERR, - stdout)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_URL, - kr->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_WRITEDATA, - &kr->db)); - kr->job = MAC_job_add (mint->ctx, - c, - GNUNET_NO, - &keys_completed_cb, - kr); - mint->kr = kr; - return mint; -} - - -/** - * Disconnect from the mint - * - * @param mint the mint handle - */ -void -TALER_MINT_disconnect (struct TALER_MINT_Handle *mint) -{ - unsigned int i; - - if (NULL != mint->kr) - { - MAC_job_cancel (mint->kr->job); - free_keys_request (mint->kr); - mint->kr = NULL; - } - GNUNET_array_grow (mint->key_data.sign_keys, - mint->key_data.num_sign_keys, - 0); - for (i=0;i<mint->key_data.num_denom_keys;i++) - GNUNET_CRYPTO_rsa_public_key_free (mint->key_data.denom_keys[i].key.rsa_public_key); - GNUNET_array_grow (mint->key_data.denom_keys, - mint->key_data.num_denom_keys, - 0); - GNUNET_array_grow (mint->key_data.auditors, - mint->key_data.num_auditors, - 0); - GNUNET_free (mint->url); - GNUNET_free (mint); -} - - -/** - * Test if the given @a pub is a the current signing key from the mint - * according to @a keys. - * - * @param keys the mint's key set - * @param pub claimed current online signing key for the mint - * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key - */ -int -TALER_MINT_test_signing_key (const struct TALER_MINT_Keys *keys, - const struct TALER_MintPublicKeyP *pub) -{ - struct GNUNET_TIME_Absolute now; - unsigned int i; - - /* we will check using a tolerance of 1h for the time */ - now = GNUNET_TIME_absolute_get (); - for (i=0;i<keys->num_sign_keys;i++) - if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) && - (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) && - (0 == memcmp (pub, - &keys->sign_keys[i].key, - sizeof (struct TALER_MintPublicKeyP))) ) - return GNUNET_OK; - return GNUNET_SYSERR; -} - - -/** - * Obtain the denomination key details from the mint. - * - * @param keys the mint's key set - * @param pk public key of the denomination to lookup - * @return details about the given denomination key, NULL if the key is - * not found - */ -const struct TALER_MINT_DenomPublicKey * -TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys, - const struct TALER_DenominationPublicKey *pk) -{ - unsigned int i; - - for (i=0;i<keys->num_denom_keys;i++) - if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key, - keys->denom_keys[i].key.rsa_public_key)) - return &keys->denom_keys[i]; - return NULL; -} - - -/** - * Obtain the denomination key details from the mint. - * - * @param keys the mint's key set - * @param hc hash of the public key of the denomination to lookup - * @return details about the given denomination key - */ -const struct TALER_MINT_DenomPublicKey * -TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys, - const struct GNUNET_HashCode *hc) -{ - unsigned int i; - - for (i=0;i<keys->num_denom_keys;i++) - if (0 == memcmp (hc, - &keys->denom_keys[i].h_key, - sizeof (struct GNUNET_HashCode))) - return &keys->denom_keys[i]; - return NULL; -} - - -/** - * Obtain the keys from the mint. - * - * @param mint the mint handle - * @return the mint's key set - */ -const struct TALER_MINT_Keys * -TALER_MINT_get_keys (const struct TALER_MINT_Handle *mint) -{ - return &mint->key_data; -} - - -/* end of mint_api_handle.c */ diff --git a/src/mint-lib/mint_api_handle.h b/src/mint-lib/mint_api_handle.h deleted file mode 100644 index 0dae58db6..000000000 --- a/src/mint-lib/mint_api_handle.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_handle.h - * @brief Internal interface to the handle part of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include "taler_mint_service.h" - - -/** - * Get the context of a mint. - * - * @param h the mint handle to query - * @return ctx context to execute jobs in - */ -struct TALER_MINT_Context * -MAH_handle_to_context (struct TALER_MINT_Handle *h); - - -/** - * Check if the handle is ready to process requests. - * - * @param h the mint handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -int -MAH_handle_is_ready (struct TALER_MINT_Handle *h); - - -/** - * Obtain the URL to use for an API request. - * - * @param h the mint handle to query - * @param path Taler API path (i.e. "/reserve/withdraw") - * @return the full URI to use with cURL - */ -char * -MAH_path_to_url (struct TALER_MINT_Handle *h, - const char *path); - - -/* end of mint_api_handle.h */ diff --git a/src/mint-lib/mint_api_json.c b/src/mint-lib/mint_api_json.c deleted file mode 100644 index 7de33e5eb..000000000 --- a/src/mint-lib/mint_api_json.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_json.c - * @brief functions to parse incoming requests (JSON snippets) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include "mint_api_json.h" - -/** - * Navigate and parse data in a JSON tree. - * - * @param root the JSON node to start the navigation at. - * @param spec parse specification array - * @return offset in @a spec where parsing failed, -1 on success (!) - */ -static int -parse_json (json_t *root, - struct MAJ_Specification *spec) -{ - int i; - json_t *pos; /* what's our current position? */ - - pos = root; - for (i=0;MAJ_CMD_END != spec[i].cmd;i++) - { - pos = json_object_get (root, - spec[i].field); - if (NULL == pos) - { - GNUNET_break_op (0); - return i; - } - switch (spec[i].cmd) - { - case MAJ_CMD_END: - GNUNET_assert (0); - return i; - case MAJ_CMD_AMOUNT: - if (GNUNET_OK != - TALER_json_to_amount (pos, - spec[i].details.amount)) - { - GNUNET_break_op (0); - return i; - } - break; - case MAJ_CMD_TIME_ABSOLUTE: - if (GNUNET_OK != - TALER_json_to_abs (pos, - spec[i].details.abs_time)) - { - GNUNET_break_op (0); - return i; - } - break; - - case MAJ_CMD_STRING: - { - const char *str; - - str = json_string_value (pos); - if (NULL == str) - { - GNUNET_break_op (0); - return i; - } - *spec[i].details.strptr = str; - } - break; - - case MAJ_CMD_BINARY_FIXED: - { - const char *str; - int res; - - str = json_string_value (pos); - if (NULL == str) - { - GNUNET_break_op (0); - return i; - } - res = GNUNET_STRINGS_string_to_data (str, strlen (str), - spec[i].details.fixed_data.dest, - spec[i].details.fixed_data.dest_size); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - return i; - } - } - break; - - case MAJ_CMD_BINARY_VARIABLE: - { - const char *str; - size_t size; - void *data; - int res; - - str = json_string_value (pos); - if (NULL == str) - { - GNUNET_break_op (0); - return i; - } - size = (strlen (str) * 5) / 8; - if (size >= 1024) - { - GNUNET_break_op (0); - return i; - } - data = GNUNET_malloc (size); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - data, - size); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - GNUNET_free (data); - return i; - } - *spec[i].details.variable_data.dest_p = data; - *spec[i].details.variable_data.dest_size_p = size; - } - break; - - case MAJ_CMD_RSA_PUBLIC_KEY: - { - size_t size; - const char *str; - int res; - void *buf; - - str = json_string_value (pos); - if (NULL == str) - { - GNUNET_break_op (0); - return i; - } - size = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (size); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - size); - if (GNUNET_OK != res) - { - GNUNET_free (buf); - GNUNET_break_op (0); - return i; - } - *spec[i].details.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_decode (buf, - size); - GNUNET_free (buf); - if (NULL == spec[i].details.rsa_public_key) - { - GNUNET_break_op (0); - return i; - } - } - break; - - case MAJ_CMD_RSA_SIGNATURE: - { - size_t size; - const char *str; - int res; - void *buf; - - str = json_string_value (pos); - if (NULL == str) - { - GNUNET_break_op (0); - return i; - } - size = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (size); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - size); - if (GNUNET_OK != res) - { - GNUNET_free (buf); - GNUNET_break_op (0); - return i; - } - *spec[i].details.rsa_signature - = GNUNET_CRYPTO_rsa_signature_decode (buf, - size); - GNUNET_free (buf); - if (NULL == spec[i].details.rsa_signature) - return i; - } - break; - - case MAJ_CMD_UINT16: - { - json_int_t val; - - if (! json_is_integer (pos)) - { - GNUNET_break_op (0); - return i; - } - val = json_integer_value (pos); - if ( (0 > val) || (val > UINT16_MAX) ) - { - GNUNET_break_op (0); - return i; - } - *spec[i].details.u16 = (uint16_t) val; - } - break; - - case MAJ_CMD_UINT64: - { - json_int_t val; - - if (! json_is_integer (pos)) - { - GNUNET_break_op (0); - return i; - } - val = json_integer_value (pos); - *spec[i].details.u64 = (uint64_t) val; - } - break; - - case MAJ_CMD_JSON_OBJECT: - { - if (! (json_is_object (pos) || json_is_array (pos)) ) - { - GNUNET_break_op (0); - return i; - } - json_incref (pos); - *spec[i].details.obj = pos; - } - break; - - default: - GNUNET_break (0); - return i; - } - } - return -1; /* all OK! */ -} - - -/** - * Free all elements allocated during a - * #MAJ_parse_json() operation. - * - * @param spec specification of the parse operation - * @param end number of elements in @a spec to process - */ -static void -parse_free (struct MAJ_Specification *spec, - int end) -{ - int i; - - for (i=0;i<end;i++) - { - switch (spec[i].cmd) - { - case MAJ_CMD_END: - GNUNET_assert (0); - return; - case MAJ_CMD_AMOUNT: - break; - case MAJ_CMD_TIME_ABSOLUTE: - break; - case MAJ_CMD_BINARY_FIXED: - break; - case MAJ_CMD_STRING: - break; - case MAJ_CMD_BINARY_VARIABLE: - GNUNET_free (*spec[i].details.variable_data.dest_p); - *spec[i].details.variable_data.dest_p = NULL; - *spec[i].details.variable_data.dest_size_p = 0; - break; - case MAJ_CMD_RSA_PUBLIC_KEY: - GNUNET_CRYPTO_rsa_public_key_free (*spec[i].details.rsa_public_key); - *spec[i].details.rsa_public_key = NULL; - break; - case MAJ_CMD_RSA_SIGNATURE: - GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature); - *spec[i].details.rsa_signature = NULL; - break; - case MAJ_CMD_JSON_OBJECT: - json_decref (*spec[i].details.obj); - *spec[i].details.obj = NULL; - break; - default: - GNUNET_break (0); - break; - } - } -} - - -/** - * Navigate and parse data in a JSON tree. - * - * @param root the JSON node to start the navigation at. - * @param spec parse specification array - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -int -MAJ_parse_json (const json_t *root, - struct MAJ_Specification *spec) -{ - int ret; - - ret = parse_json ((json_t *) root, - spec); - if (-1 == ret) - return GNUNET_OK; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "JSON field `%s` (%d) had unexpected value\n", - spec[ret].field, - ret); - parse_free (spec, ret); - return GNUNET_SYSERR; -} - - -/** - * Free all elements allocated during a - * #MAJ_parse_json() operation. - * - * @param spec specification of the parse operation - */ -void -MAJ_parse_free (struct MAJ_Specification *spec) -{ - int i; - - for (i=0;MAJ_CMD_END != spec[i].cmd;i++) ; - parse_free (spec, i); -} - - -/** - * The expected field stores a string. - * - * @param name name of the JSON field - * @param strptr where to store a pointer to the field - */ -struct MAJ_Specification -MAJ_spec_string (const char *name, - const char **strptr) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_STRING, - .field = name, - .details.strptr = strptr - }; - return ret; -} - - -/** - * Specification for parsing an absolute time value. - * - * @param name name of the JSON field - * @param at where to store the absolute time found under @a name - */ -struct MAJ_Specification -MAJ_spec_absolute_time (const char *name, - struct GNUNET_TIME_Absolute *at) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_TIME_ABSOLUTE, - .field = name, - .details.abs_time = at - }; - return ret; -} - - -/** - * Specification for parsing an amount value. - * - * @param name name of the JSON field - * @param amount where to store the amount found under @a name - */ -struct MAJ_Specification -MAJ_spec_amount (const char *name, - struct TALER_Amount *amount) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_AMOUNT, - .field = name, - .details.amount = amount - }; - return ret; -} - - -/** - * 16-bit integer. - * - * @param name name of the JSON field - * @param[out] u16 where to store the integer found under @a name - */ -struct MAJ_Specification -MAJ_spec_uint16 (const char *name, - uint16_t *u16) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_UINT16, - .field = name, - .details.u16 = u16 - }; - return ret; -} - - -/** - * 64-bit integer. - * - * @param name name of the JSON field - * @param[out] u64 where to store the integer found under @a name - */ -struct MAJ_Specification -MAJ_spec_uint64 (const char *name, - uint64_t *u64) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_UINT64, - .field = name, - .details.u64 = u64 - }; - return ret; -} - - -/** - * JSON object. - * - * @param name name of the JSON field - * @param[out] jsonp where to store the JSON found under @a name - */ -struct MAJ_Specification -MAJ_spec_json (const char *name, - json_t **jsonp) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_JSON_OBJECT, - .field = name, - .details.obj = jsonp - }; - return ret; -} - - -/** - * Specification for parsing an RSA public key. - * - * @param name name of the JSON field - * @param pk where to store the RSA key found under @a name - */ -struct MAJ_Specification -MAJ_spec_rsa_public_key (const char *name, - struct GNUNET_CRYPTO_rsa_PublicKey **pk) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_RSA_PUBLIC_KEY, - .field = name, - .details.rsa_public_key = pk - }; - return ret; -} - - -/** - * Specification for parsing an RSA signature. - * - * @param name name of the JSON field - * @param sig where to store the RSA signature found under @a name - */ -struct MAJ_Specification -MAJ_spec_rsa_signature (const char *name, - struct GNUNET_CRYPTO_rsa_Signature **sig) -{ - struct MAJ_Specification ret = - { - .cmd = MAJ_CMD_RSA_SIGNATURE, - .field = name, - .details.rsa_signature = sig - }; - return ret; -} - - -/* end of mint_api_json.c */ diff --git a/src/mint-lib/mint_api_json.h b/src/mint-lib/mint_api_json.h deleted file mode 100644 index 6bc3a5572..000000000 --- a/src/mint-lib/mint_api_json.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_json.h - * @brief functions to parse incoming requests (JSON snippets) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler_util.h" -#include <jansson.h> - - -/** - * Enumeration with the various commands for the - * #MAJ_parse_json interpreter. - */ -enum MAJ_Command -{ - - /** - * End of command list. - */ - MAJ_CMD_END, - - /** - * Parse amount at current position. - */ - MAJ_CMD_AMOUNT, - - /** - * Parse absolute time at current position. - */ - MAJ_CMD_TIME_ABSOLUTE, - - /** - * Parse fixed binary value at current position. - */ - MAJ_CMD_BINARY_FIXED, - - /** - * Parse variable-size binary value at current position. - */ - MAJ_CMD_BINARY_VARIABLE, - - /** - * Parse RSA public key at current position. - */ - MAJ_CMD_RSA_PUBLIC_KEY, - - /** - * Parse RSA signature at current position. - */ - MAJ_CMD_RSA_SIGNATURE, - - /** - * Parse `const char *` JSON string at current position. - */ - MAJ_CMD_STRING, - - /** - * Parse `uint16_t` integer at the current position. - */ - MAJ_CMD_UINT16, - - /** - * Parse `uint64_t` integer at the current position. - */ - MAJ_CMD_UINT64, - - /** - * Parse JSON object at the current position. - */ - MAJ_CMD_JSON_OBJECT, - - /** - * Parse ??? at current position. - */ - MAJ_CMD_C - -}; - - -/** - * @brief Entry in parser specification for #MAJ_parse_json. - */ -struct MAJ_Specification -{ - - /** - * Command to execute. - */ - enum MAJ_Command cmd; - - /** - * Name of the field to access. - */ - const char *field; - - /** - * Further details for the command. - */ - union { - - /** - * Where to store amount for #MAJ_CMD_AMOUNT. - */ - struct TALER_Amount *amount; - - /** - * Where to store time, for #MAJ_CMD_TIME_ABSOLUTE. - */ - struct GNUNET_TIME_Absolute *abs_time; - - /** - * Where to write binary data, for #MAJ_CMD_BINARY_FIXED. - */ - struct { - /** - * Where to write the data. - */ - void *dest; - - /** - * How many bytes to write to @e dest. - */ - size_t dest_size; - - } fixed_data; - - /** - * Where to write binary data, for #MAJ_CMD_BINARY_VARIABLE. - */ - struct { - /** - * Where to store the pointer with the data (is allocated). - */ - void **dest_p; - - /** - * Where to store the number of bytes allocated at `*dest`. - */ - size_t *dest_size_p; - - } variable_data; - - /** - * Where to store the RSA public key for #MAJ_CMD_RSA_PUBLIC_KEY - */ - struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key; - - /** - * Where to store the RSA signature for #MAJ_CMD_RSA_SIGNATURE - */ - struct GNUNET_CRYPTO_rsa_Signature **rsa_signature; - - /** - * Details for #MAJ_CMD_EDDSA_SIGNATURE - */ - struct { - - /** - * Where to store the purpose. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose **purpose_p; - - /** - * Key to verify the signature against. - */ - const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key; - - } eddsa_signature; - - /** - * Where to store a pointer to the string. - */ - const char **strptr; - - /** - * Where to store 16-bit integer. - */ - uint16_t *u16; - - /** - * Where to store 64-bit integer. - */ - uint64_t *u64; - - /** - * Where to store a JSON object. - */ - json_t **obj; - - } details; - -}; - - -/** - * Navigate and parse data in a JSON tree. - * - * @param root the JSON node to start the navigation at. - * @param spec parse specification array - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -int -MAJ_parse_json (const json_t *root, - struct MAJ_Specification *spec); - - -/** - * Free all elements allocated during a - * #MAJ_parse_json() operation. - * - * @param spec specification of the parse operation - */ -void -MAJ_parse_free (struct MAJ_Specification *spec); - - -/** - * End of a parser specification. - */ -#define MAJ_spec_end { .cmd = MAJ_CMD_END } - -/** - * Fixed size object (in network byte order, encoded using Crockford - * Base32hex encoding). - * - * @param name name of the JSON field - * @param obj pointer where to write the data (type of `*obj` will determine size) - */ -#define MAJ_spec_fixed_auto(name,obj) { .cmd = MAJ_CMD_BINARY_FIXED, .field = name, .details.fixed_data.dest = obj, .details.fixed_data.dest_size = sizeof (*obj) } - - -/** - * Variable size object (in network byte order, encoded using Crockford - * Base32hex encoding). - * - * @param name name of the JSON field - * @param obj pointer where to write the data (a `void **`) - * @param size where to store the number of bytes allocated for @a obj (of type `size_t *` - */ -#define MAJ_spec_varsize(name,obj,size) { .cmd = MAJ_CMD_BINARY_VARIABLE, .field = name, .details.variable_data.dest_p = obj, .details.variable_data.dest_size_p = size } - - -/** - * The expected field stores a string. - * - * @param name name of the JSON field - * @param strptr where to store a pointer to the field - */ -struct MAJ_Specification -MAJ_spec_string (const char *name, - const char **strptr); - - -/** - * Absolute time. - * - * @param name name of the JSON field - * @param[out] at where to store the absolute time found under @a name - */ -struct MAJ_Specification -MAJ_spec_absolute_time (const char *name, - struct GNUNET_TIME_Absolute *at); - - -/** - * 16-bit integer. - * - * @param name name of the JSON field - * @param[out] u16 where to store the integer found under @a name - */ -struct MAJ_Specification -MAJ_spec_uint16 (const char *name, - uint16_t *u16); - - -/** - * 64-bit integer. - * - * @param name name of the JSON field - * @param[out] u64 where to store the integer found under @a name - */ -struct MAJ_Specification -MAJ_spec_uint64 (const char *name, - uint64_t *u64); - - -/** - * JSON object. - * - * @param name name of the JSON field - * @param[out] jsonp where to store the JSON found under @a name - */ -struct MAJ_Specification -MAJ_spec_json (const char *name, - json_t **jsonp); - - -/** - * Specification for parsing an amount value. - * - * @param name name of the JSON field - * @param amount where to store the amount under @a name - */ -struct MAJ_Specification -MAJ_spec_amount (const char *name, - struct TALER_Amount *amount); - - -/** - * Specification for parsing an RSA public key. - * - * @param name name of the JSON field - * @param pk where to store the RSA key found under @a name - */ -struct MAJ_Specification -MAJ_spec_rsa_public_key (const char *name, - struct GNUNET_CRYPTO_rsa_PublicKey **pk); - - -/** - * Specification for parsing an RSA signature. - * - * @param name name of the JSON field - * @param sig where to store the RSA signature found under @a name - */ -struct MAJ_Specification -MAJ_spec_rsa_signature (const char *name, - struct GNUNET_CRYPTO_rsa_Signature **sig); - - - - -/* end of mint_api_json.h */ diff --git a/src/mint-lib/mint_api_refresh.c b/src/mint-lib/mint_api_refresh.c deleted file mode 100644 index cea16b153..000000000 --- a/src/mint-lib/mint_api_refresh.c +++ /dev/null @@ -1,2061 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_refresh.c - * @brief Implementation of the /refresh/melt+reveal requests of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/* ********************* /refresh/ common ***************************** */ - -/* structures for committing refresh data to disk before doing the - network interaction(s) */ - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Header of serialized information about a coin we are melting. - */ -struct MeltedCoinP -{ - /** - * Private key of the coin. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Amount this coin contributes to the melt, including fee. - */ - struct TALER_AmountNBO melt_amount_with_fee; - - /** - * The applicable fee for withdrawing a coin of this denomination - */ - struct TALER_AmountNBO fee_melt; - - /** - * The original value of the coin. - */ - struct TALER_AmountNBO original_value; - - /** - * Transfer private keys for each cut-and-choose dimension. - */ - struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA]; - - /** - * Timestamp indicating when coins of this denomination become invalid. - */ - struct GNUNET_TIME_AbsoluteNBO deposit_valid_until; - - /** - * Size of the encoded public key that follows. - */ - uint16_t pbuf_size; - - /** - * Size of the encoded signature that follows. - */ - uint16_t sbuf_size; - - /* Followed by serializations of: - 1) struct TALER_DenominationPublicKey pub_key; - 2) struct TALER_DenominationSignature sig; - */ -}; - - -/** - * Header for serializations of coin-specific information about the - * fresh coins we generate during a melt. - */ -struct FreshCoinP -{ - - /** - * Private key of the coin. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Size of the encoded blinding key that follows. - */ - uint32_t bbuf_size; - - /* Followed by serialization of: - - struct TALER_DenominationBlindingKey blinding_key; - */ - -}; - - -/** - * Header of serialized data about a melt operation, suitable for - * persisting it on disk. - */ -struct MeltDataP -{ - - /** - * Hash over the melting session. - */ - struct GNUNET_HashCode melt_session_hash; - - /** - * Link secret used to encrypt the @a coin_priv and the blinding - * key in the linkage data for the respective cut-and-choose dimension. - */ - struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA]; - - /** - * Number of coins we are melting, in NBO - */ - uint16_t num_melted_coins GNUNET_PACKED; - - /** - * Number of coins we are creating, in NBO - */ - uint16_t num_fresh_coins GNUNET_PACKED; - - /* Followed by serializations of: - 1) struct MeltedCoinP melted_coins[num_melted_coins]; - 2) struct TALER_MINT_DenomPublicKey fresh_pks[num_fresh_coins]; - 3) TALER_CNC_KAPPA times: - 3a) struct FreshCoinP fresh_coins[num_fresh_coins]; - */ -}; - - -GNUNET_NETWORK_STRUCT_END - - -/** - * Information about a coin we are melting. - */ -struct MeltedCoin -{ - /** - * Private key of the coin. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Amount this coin contributes to the melt, including fee. - */ - struct TALER_Amount melt_amount_with_fee; - - /** - * The applicable fee for melting a coin of this denomination - */ - struct TALER_Amount fee_melt; - - /** - * The original value of the coin. - */ - struct TALER_Amount original_value; - - /** - * Transfer private keys for each cut-and-choose dimension. - */ - struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA]; - - /** - * Timestamp indicating when coins of this denomination become invalid. - */ - struct GNUNET_TIME_Absolute deposit_valid_until; - - /** - * Denomination key of the original coin. - */ - struct TALER_DenominationPublicKey pub_key; - - /** - * Mint's signature over the coin. - */ - struct TALER_DenominationSignature sig; - -}; - - -/** - * Coin-specific information about the fresh coins we generate during - * a melt. - */ -struct FreshCoin -{ - - /** - * Private key of the coin. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Blinding key used for blinding during blind signing. - */ - struct TALER_DenominationBlindingKey blinding_key; - -}; - - -/** - * Melt data in non-serialized format for convenient processing. - */ -struct MeltData -{ - - /** - * Hash over the melting session. - */ - struct GNUNET_HashCode melt_session_hash; - - /** - * Link secrets for each cut-and-choose dimension. - */ - struct TALER_LinkSecretP link_secrets[TALER_CNC_KAPPA]; - - /** - * Number of coins we are melting - */ - uint16_t num_melted_coins; - - /** - * Number of coins we are creating - */ - uint16_t num_fresh_coins; - - /** - * Information about the melted coins in an array of length @e - * num_melted_coins. - */ - struct MeltedCoin *melted_coins; - - /** - * Array of @e num_fresh_coins denomination keys for the coins to be - * freshly minted. - */ - struct TALER_DenominationPublicKey *fresh_pks; - - /** - * Arrays of @e num_fresh_coins with information about the fresh - * coins to be created, for each cut-and-choose dimension. - */ - struct FreshCoin *fresh_coins[TALER_CNC_KAPPA]; -}; - - -/** - * Free all information associated with a melted coin session. - * - * @param mc melted coin to release, the pointer itself is NOT - * freed (as it is typically not allocated by itself) - */ -static void -free_melted_coin (struct MeltedCoin *mc) -{ - if (NULL == mc) - return; - if (NULL != mc->pub_key.rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (mc->pub_key.rsa_public_key); - if (NULL != mc->sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (mc->sig.rsa_signature); -} - - -/** - * Free all information associated with a fresh coin. - * - * @param fc fresh coin to release, the pointer itself is NOT - * freed (as it is typically not allocated by itself) - */ -static void -free_fresh_coin (struct FreshCoin *fc) -{ - if (NULL == fc) - return; - if (NULL != fc->blinding_key.rsa_blinding_key) - GNUNET_CRYPTO_rsa_blinding_key_free (fc->blinding_key.rsa_blinding_key); -} - - -/** - * Free all information associated with a melting session. Note - * that we allow the melting session to be only partially initialized, - * as we use this function also when freeing melt data that was not - * fully initialized (i.e. due to failures in #deserialize_melt_data()). - * - * @param md melting data to release, the pointer itself is NOT - * freed (as it is typically not allocated by itself) - */ -static void -free_melt_data (struct MeltData *md) -{ - unsigned int i; - unsigned int j; - - if (NULL != md->melted_coins) - { - for (i=0;i<md->num_melted_coins;i++) - free_melted_coin (&md->melted_coins[i]); - GNUNET_free (md->melted_coins); - } - if (NULL != md->fresh_pks) - { - for (i=0;i<md->num_fresh_coins;i++) - if (NULL != md->fresh_pks[i].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key); - GNUNET_free (md->fresh_pks); - } - - for (i=0;i<TALER_CNC_KAPPA;i++) - { - for (j=0;j<md->num_fresh_coins;j++) - free_fresh_coin (&md->fresh_coins[i][j]); - GNUNET_free (md->fresh_coins[i]); - } - /* Finally, clean up a bit... - (NOTE: compilers might optimize this away, so this is - not providing any strong assurances that the key material - is purged.) */ - memset (md, - 0, - sizeof (struct MeltData)); -} - - -/** - * Serialize information about a coin we are melting. - * - * @param mc information to serialize - * @param buf buffer to write data in, NULL to just compute - * required size - * @param off offeset at @a buf to use - * @return number of bytes written to @a buf at @a off, or if - * @a buf is NULL, number of bytes required; 0 on error - */ -static size_t -serialize_melted_coin (const struct MeltedCoin *mc, - char *buf, - size_t off) -{ - struct MeltedCoinP mcp; - unsigned int i; - char *pbuf; - size_t pbuf_size; - char *sbuf; - size_t sbuf_size; - - sbuf_size = GNUNET_CRYPTO_rsa_signature_encode (mc->sig.rsa_signature, - &sbuf); - pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (mc->pub_key.rsa_public_key, - &pbuf); - if (NULL == buf) - { - GNUNET_free (sbuf); - GNUNET_free (pbuf); - return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size; - } - if ( (sbuf_size > UINT16_MAX) || - (pbuf_size > UINT16_MAX) ) - { - GNUNET_break (0); - return 0; - } - mcp.coin_priv = mc->coin_priv; - TALER_amount_hton (&mcp.melt_amount_with_fee, - &mc->melt_amount_with_fee); - TALER_amount_hton (&mcp.fee_melt, - &mc->fee_melt); - TALER_amount_hton (&mcp.original_value, - &mc->original_value); - for (i=0;i<TALER_CNC_KAPPA;i++) - mcp.transfer_priv[i] = mc->transfer_priv[i]; - mcp.deposit_valid_until = GNUNET_TIME_absolute_hton (mc->deposit_valid_until); - mcp.pbuf_size = htons ((uint16_t) pbuf_size); - mcp.sbuf_size = htons ((uint16_t) sbuf_size); - memcpy (&buf[off], - &mcp, - sizeof (struct MeltedCoinP)); - memcpy (&buf[off + sizeof (struct MeltedCoinP)], - pbuf, - pbuf_size); - memcpy (&buf[off + sizeof (struct MeltedCoinP) + pbuf_size], - sbuf, - sbuf_size); - GNUNET_free (sbuf); - GNUNET_free (pbuf); - return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size; -} - - -/** - * Deserialize information about a coin we are melting. - * - * @param[out] mc information to deserialize - * @param buf buffer to read data from - * @param size number of bytes available at @a buf to use - * @param[out] ok set to #GNUNET_NO to report errors - * @return number of bytes read from @a buf, 0 on error - */ -static size_t -deserialize_melted_coin (struct MeltedCoin *mc, - const char *buf, - size_t size, - int *ok) -{ - struct MeltedCoinP mcp; - unsigned int i; - size_t pbuf_size; - size_t sbuf_size; - size_t off; - - if (size < sizeof (struct MeltedCoinP)) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - memcpy (&mcp, - buf, - sizeof (struct MeltedCoinP)); - pbuf_size = ntohs (mcp.pbuf_size); - sbuf_size = ntohs (mcp.sbuf_size); - if (size < sizeof (struct MeltedCoinP) + pbuf_size + sbuf_size) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - off = sizeof (struct MeltedCoinP); - mc->pub_key.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_decode (&buf[off], - pbuf_size); - off += pbuf_size; - mc->sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_decode (&buf[off], - sbuf_size); - off += sbuf_size; - if ( (NULL == mc->pub_key.rsa_public_key) || - (NULL == mc->sig.rsa_signature) ) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - - mc->coin_priv = mcp.coin_priv; - TALER_amount_ntoh (&mc->melt_amount_with_fee, - &mcp.melt_amount_with_fee); - TALER_amount_ntoh (&mc->fee_melt, - &mcp.fee_melt); - TALER_amount_ntoh (&mc->original_value, - &mcp.original_value); - for (i=0;i<TALER_CNC_KAPPA;i++) - mc->transfer_priv[i] = mcp.transfer_priv[i]; - mc->deposit_valid_until = GNUNET_TIME_absolute_ntoh (mcp.deposit_valid_until); - return off; -} - - -/** - * Serialize information about a denomination key. - * - * @param dk information to serialize - * @param buf buffer to write data in, NULL to just compute - * required size - * @param off offeset at @a buf to use - * @return number of bytes written to @a buf at @a off, or if - * @a buf is NULL, number of bytes required - */ -static size_t -serialize_denomination_key (const struct TALER_DenominationPublicKey *dk, - char *buf, - size_t off) -{ - char *pbuf; - size_t pbuf_size; - uint32_t be; - - pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key, - &pbuf); - if (NULL == buf) - { - GNUNET_free (pbuf); - return pbuf_size + sizeof (uint32_t); - } - be = htonl ((uint32_t) pbuf_size); - memcpy (&buf[off], - &be, - sizeof (uint32_t)); - memcpy (&buf[off + sizeof (uint32_t)], - pbuf, - pbuf_size); - GNUNET_free (pbuf); - return pbuf_size + sizeof (uint32_t); -} - - -/** - * Deserialize information about a denomination key. - * - * @param[out] dk information to deserialize - * @param buf buffer to read data from - * @param size number of bytes available at @a buf to use - * @param[out] ok set to #GNUNET_NO to report errors - * @return number of bytes read from @a buf, 0 on error - */ -static size_t -deserialize_denomination_key (struct TALER_DenominationPublicKey *dk, - const char *buf, - size_t size, - int *ok) -{ - size_t pbuf_size; - uint32_t be; - - if (size < sizeof (uint32_t)) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - memcpy (&be, - buf, - sizeof (uint32_t)); - pbuf_size = ntohl (be); - if (size < sizeof (uint32_t) + pbuf_size) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - dk->rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)], - pbuf_size); - - if (NULL == dk->rsa_public_key) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - return sizeof (uint32_t) + pbuf_size; -} - - -/** - * Serialize information about a fresh coin we are generating. - * - * @param fc information to serialize - * @param buf buffer to write data in, NULL to just compute - * required size - * @param off offeset at @a buf to use - * @return number of bytes written to @a buf at @a off, or if - * @a buf is NULL, number of bytes required - */ -static size_t -serialize_fresh_coin (const struct FreshCoin *fc, - char *buf, - size_t off) -{ - struct FreshCoinP fcp; - char *bbuf; - size_t bbuf_size; - - bbuf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (fc->blinding_key.rsa_blinding_key, - &bbuf); - if (NULL == buf) - { - GNUNET_free (bbuf); - return sizeof (struct FreshCoinP) + bbuf_size; - } - fcp.coin_priv = fc->coin_priv; - fcp.bbuf_size = htonl ((uint32_t) bbuf_size); - memcpy (&buf[off], - &fcp, - sizeof (struct FreshCoinP)); - memcpy (&buf[off + sizeof (struct FreshCoinP)], - bbuf, - bbuf_size); - GNUNET_free (bbuf); - return sizeof (struct FreshCoinP) + bbuf_size; -} - - -/** - * Deserialize information about a fresh coin we are generating. - * - * @param[out] fc information to deserialize - * @param buf buffer to read data from - * @param size number of bytes available at @a buf to use - * @param[out] ok set to #GNUNET_NO to report errors - * @return number of bytes read from @a buf, 0 on error - */ -static size_t -deserialize_fresh_coin (struct FreshCoin *fc, - const char *buf, - size_t size, - int *ok) -{ - struct FreshCoinP fcp; - size_t bbuf_size; - - if (size < sizeof (struct FreshCoinP)) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - memcpy (&fcp, - buf, - sizeof (struct FreshCoinP)); - bbuf_size = ntohl (fcp.bbuf_size); - if (size < sizeof (struct FreshCoinP) + bbuf_size) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - fc->blinding_key.rsa_blinding_key - = GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct FreshCoinP)], - bbuf_size); - if (NULL == fc->blinding_key.rsa_blinding_key) - { - GNUNET_break (0); - *ok = GNUNET_NO; - return 0; - } - fc->coin_priv = fcp.coin_priv; - return sizeof (struct FreshCoinP) + bbuf_size; -} - - -/** - * Serialize melt data. - * - * @param md data to serialize - * @param[out] res_size size of buffer returned - * @return serialized melt data - */ -static char * -serialize_melt_data (const struct MeltData *md, - size_t *res_size) -{ - size_t size; - size_t asize; - char *buf; - unsigned int i; - unsigned int j; - - size = 0; - asize = (size_t) -1; /* make the compiler happy */ - buf = NULL; - /* we do 2 iterations, #1 to determine total size, #2 to - actually construct the buffer */ - do { - if (0 == size) - { - size = sizeof (struct MeltDataP); - } - else - { - struct MeltDataP *mdp; - - buf = GNUNET_malloc (size); - asize = size; /* just for invariant check later */ - size = sizeof (struct MeltDataP); - mdp = (struct MeltDataP *) buf; - mdp->melt_session_hash = md->melt_session_hash; - for (i=0;i<TALER_CNC_KAPPA;i++) - mdp->link_secrets[i] = md->link_secrets[i]; - mdp->num_melted_coins = htons (md->num_melted_coins); - mdp->num_fresh_coins = htons (md->num_fresh_coins); - } - for (i=0;i<md->num_melted_coins;i++) - size += serialize_melted_coin (&md->melted_coins[i], - buf, - size); - for (i=0;i<md->num_fresh_coins;i++) - size += serialize_denomination_key (&md->fresh_pks[i], - buf, - size); - for (i=0;i<TALER_CNC_KAPPA;i++) - for(j=0;j<md->num_fresh_coins;j++) - size += serialize_fresh_coin (&md->fresh_coins[i][j], - buf, - size); - } while (NULL == buf); - GNUNET_assert (size == asize); - *res_size = size; - return buf; -} - - -/** - * Deserialize melt data. - * - * @param buf serialized data - * @param buf_size size of @a buf - * @return deserialized melt data, NULL on error - */ -static struct MeltData * -deserialize_melt_data (const char *buf, - size_t buf_size) -{ - struct MeltData *md; - struct MeltDataP mdp; - unsigned int i; - unsigned int j; - size_t off; - int ok; - - if (buf_size < sizeof (struct MeltDataP)) - return NULL; - memcpy (&mdp, - buf, - sizeof (struct MeltDataP)); - md = GNUNET_new (struct MeltData); - md->melt_session_hash = mdp.melt_session_hash; - for (i=0;i<TALER_CNC_KAPPA;i++) - md->link_secrets[i] = mdp.link_secrets[i]; - md->num_melted_coins = ntohs (mdp.num_melted_coins); - md->num_fresh_coins = ntohs (mdp.num_fresh_coins); - md->melted_coins = GNUNET_new_array (md->num_melted_coins, - struct MeltedCoin); - md->fresh_pks = GNUNET_new_array (md->num_fresh_coins, - struct TALER_DenominationPublicKey); - for (i=0;i<TALER_CNC_KAPPA;i++) - md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins, - struct FreshCoin); - off = sizeof (struct MeltDataP); - ok = GNUNET_YES; - for (i=0;(i<md->num_melted_coins)&&(GNUNET_YES == ok);i++) - off += deserialize_melted_coin (&md->melted_coins[i], - &buf[off], - buf_size - off, - &ok); - for (i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++) - off += deserialize_denomination_key (&md->fresh_pks[i], - &buf[off], - buf_size - off, - &ok); - - for (i=0;i<TALER_CNC_KAPPA;i++) - for(j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++) - off += deserialize_fresh_coin (&md->fresh_coins[i][j], - &buf[off], - buf_size - off, - &ok); - if (off != buf_size) - { - GNUNET_break (0); - ok = GNUNET_NO; - } - if (GNUNET_YES != ok) - { - free_melt_data (md); - GNUNET_free (md); - return NULL; - } - return md; -} - - -/** - * Setup information for a fresh coin. - * - * @param[out] fc value to initialize - * @param pk denomination information for the fresh coin - */ -static void -setup_fresh_coin (struct FreshCoin *fc, - const struct TALER_MINT_DenomPublicKey *pk) -{ - struct GNUNET_CRYPTO_EddsaPrivateKey *epk; - unsigned int len; - - epk = GNUNET_CRYPTO_eddsa_key_create (); - fc->coin_priv.eddsa_priv = *epk; - GNUNET_free (epk); - len = GNUNET_CRYPTO_rsa_public_key_len (pk->key.rsa_public_key); - fc->blinding_key.rsa_blinding_key - = GNUNET_CRYPTO_rsa_blinding_key_create (len); -} - - -/** - * Melt (partially spent) coins to obtain fresh coins that are - * unlinkable to the original coin(s). Note that melting more - * than one coin in a single request will make those coins linkable, - * so the safest operation only melts one coin at a time. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, is operation does - * not actually initiate the request. Instead, it generates a buffer - * which the caller must store before proceeding with the actual call - * to #TALER_MINT_refresh_melt() that will generate the request. - * - * This function does verify that the given request data is internally - * consistent. However, the @a melts_sigs are only verified if - * @a check_sigs is set to #GNUNET_YES, as this may be relatively - * expensive and should be redundant. - * - * Aside from some non-trivial cryptographic operations that might - * take a bit of CPU time to complete, this function returns - * its result immediately and does not start any asynchronous - * processing. This function is also thread-safe. - * - * @param num_melts number of coins that are being melted (typically 1) - * @param melt_privs array of @a num_melts private keys of the coins to melt - * @param melt_amounts array of @a num_melts amounts specifying how much - * each coin will contribute to the melt (including fee) - * @param melt_sigs array of @a num_melts signatures affirming the - * validity of the public keys corresponding to the - * @a melt_privs private keys - * @param melt_pks array of @a num_melts denomination key information - * records corresponding to the @a melt_sigs - * validity of the keys - * @param check_sigs verify the validity of the signatures of @a melt_sigs - * @param fresh_pks_len length of the @a pks array - * @param fresh_pks array of @a pks_len denominations of fresh coins to create - * @param[out] res_size set to the size of the return value, or 0 on error - * @return NULL - * if the inputs are invalid (i.e. denomination key not with this mint). - * Otherwise, pointer to a buffer of @a res_size to store persistently - * before proceeding to #TALER_MINT_refresh_melt(). - * Non-null results should be freed using #GNUNET_free(). - */ -char * -TALER_MINT_refresh_prepare (unsigned int num_melts, - const struct TALER_CoinSpendPrivateKeyP *melt_privs, - const struct TALER_Amount *melt_amounts, - const struct TALER_DenominationSignature *melt_sigs, - const struct TALER_MINT_DenomPublicKey *melt_pks, - int check_sigs, - unsigned int fresh_pks_len, - const struct TALER_MINT_DenomPublicKey *fresh_pks, - size_t *res_size) -{ - struct MeltData md; - char *buf; - unsigned int i; - unsigned int j; - struct GNUNET_HashContext *hash_context; - - /* build up melt data structure */ - for (i=0;i<TALER_CNC_KAPPA;i++) - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, - &md.link_secrets[i], - sizeof (struct TALER_LinkSecretP)); - md.num_melted_coins = num_melts; - md.num_fresh_coins = fresh_pks_len; - md.melted_coins = GNUNET_new_array (num_melts, - struct MeltedCoin); - for (i=0;i<num_melts;i++) - { - md.melted_coins[i].coin_priv = melt_privs[i]; - md.melted_coins[i].melt_amount_with_fee = melt_amounts[i]; - md.melted_coins[i].fee_melt = melt_pks[i].fee_refresh; - md.melted_coins[i].original_value = melt_pks[i].value; - for (j=0;j<TALER_CNC_KAPPA;j++) - { - struct GNUNET_CRYPTO_EcdhePrivateKey *tpk; - - tpk = GNUNET_CRYPTO_ecdhe_key_create (); - md.melted_coins[i].transfer_priv[j].ecdhe_priv = *tpk; - GNUNET_free (tpk); - } - md.melted_coins[i].deposit_valid_until - = melt_pks[i].deposit_valid_until; - md.melted_coins[i].pub_key.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (melt_pks[i].key.rsa_public_key); - md.melted_coins[i].sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (melt_sigs[i].rsa_signature); - } - md.fresh_pks = GNUNET_new_array (fresh_pks_len, - struct TALER_DenominationPublicKey); - for (i=0;i<fresh_pks_len;i++) - md.fresh_pks[i].rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key); - for (i=0;i<TALER_CNC_KAPPA;i++) - { - md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len, - struct FreshCoin); - for (j=0;j<fresh_pks_len;j++) - setup_fresh_coin (&md.fresh_coins[i][j], - &fresh_pks[j]); - } - - /* now compute melt session hash */ - hash_context = GNUNET_CRYPTO_hash_context_start (); - for (i=0;i<fresh_pks_len;i++) - { - char *buf; - size_t buf_size; - - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key, - &buf); - GNUNET_CRYPTO_hash_context_read (hash_context, - buf, - buf_size); - GNUNET_free (buf); - } - for (i=0;i<num_melts;i++) - { - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_AmountNBO melt_amount; - - GNUNET_CRYPTO_eddsa_key_get_public (&melt_privs[i].eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash_context_read (hash_context, - &coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - TALER_amount_hton (&melt_amount, - &melt_amounts[i]); - GNUNET_CRYPTO_hash_context_read (hash_context, - &melt_amount, - sizeof (struct TALER_AmountNBO)); - - } - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - for (j = 0; j < fresh_pks_len; j++) - { - const struct FreshCoin *fc; /* coin this is about */ - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode coin_hash; - char *coin_ev; /* blinded message to be signed (in envelope) for each coin */ - size_t coin_ev_size; - struct TALER_RefreshLinkDecrypted rld; - struct TALER_RefreshLinkEncrypted *rle; - char *link_enc; /* encrypted link data */ - size_t link_enc_size; - - fc = &md.fresh_coins[i][j]; - GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), - &coin_hash); - coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash, - fc->blinding_key.rsa_blinding_key, - md.fresh_pks[j].rsa_public_key, - &coin_ev); - GNUNET_CRYPTO_hash_context_read (hash_context, - coin_ev, - coin_ev_size); - GNUNET_free (coin_ev); - - rld.coin_priv = fc->coin_priv; - rld.blinding_key = fc->blinding_key; - rle = TALER_refresh_encrypt (&rld, - &md.link_secrets[i]); - link_enc = TALER_refresh_link_encrypted_encode (rle, - &link_enc_size); - - GNUNET_CRYPTO_hash_context_read (hash_context, - link_enc, - link_enc_size); - GNUNET_free (link_enc); - } - } - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - for (j = 0; j < num_melts; j++) - { - struct TALER_RefreshCommitLinkP rcl; - struct TALER_TransferSecretP trans_sec; - - GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coins[j].transfer_priv[i].ecdhe_priv, - &rcl.transfer_pub.ecdhe_pub); - TALER_link_derive_transfer_secret (&melt_privs[j], - &md.melted_coins[j].transfer_priv[i], - &trans_sec); - TALER_transfer_encrypt (&md.link_secrets[i], - &trans_sec, - &rcl.shared_secret_enc); - GNUNET_CRYPTO_hash_context_read (hash_context, - &rcl, - sizeof (struct TALER_RefreshCommitLinkP)); - } - } - - GNUNET_CRYPTO_hash_context_finish (hash_context, - &md.melt_session_hash); - - /* finally, serialize everything */ - buf = serialize_melt_data (&md, - res_size); - free_melt_data (&md); - return buf; -} - - -/* ********************* /refresh/melt ***************************** */ - - -/** - * @brief A /refresh/melt Handle - */ -struct TALER_MINT_RefreshMeltHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with refresh melt failure results. - */ - TALER_MINT_RefreshMeltCallback melt_cb; - - /** - * Closure for @e result_cb and @e melt_failure_cb. - */ - void *melt_cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Actual information about the melt operation. - */ - struct MeltData *md; -}; - - -/** - * Verify that the signature on the "200 OK" response - * from the mint is valid. - * - * @param rmh melt handle - * @param json json reply with the signature - * @param[out] noreveal_index set to the noreveal index selected by the mint - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static int -verify_refresh_melt_signature_ok (struct TALER_MINT_RefreshMeltHandle *rmh, - json_t *json, - uint16_t *noreveal_index) -{ - struct TALER_MintSignatureP mint_sig; - struct TALER_MintPublicKeyP mint_pub; - const struct TALER_MINT_Keys *key_state; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("mint_sig", &mint_sig), - MAJ_spec_fixed_auto ("mint_pub", &mint_pub), - MAJ_spec_uint16 ("noreveal_index", noreveal_index), - MAJ_spec_end - }; - struct TALER_RefreshMeltConfirmationPS confirm; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* check that mint signing key is permitted */ - key_state = TALER_MINT_get_keys (rmh->mint); - if (GNUNET_OK != - TALER_MINT_test_signing_key (key_state, - &mint_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* check that noreveal index is in permitted range */ - if (TALER_CNC_KAPPA <= *noreveal_index) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* verify signature by mint */ - confirm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_MELT); - confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS)); - confirm.session_hash = rmh->md->melt_session_hash; - confirm.noreveal_index = htons (*noreveal_index); - confirm.reserved = htons (0); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_MELT, - &confirm.purpose, - &mint_sig.eddsa_signature, - &mint_pub.eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Verify that the signatures on the "403 FORBIDDEN" response from the - * mint demonstrating customer double-spending are valid. - * - * @param rmh melt handle - * @param json json reply with the signature(s) and transaction history - * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not - */ -static int -verify_refresh_melt_signature_forbidden (struct TALER_MINT_RefreshMeltHandle *rmh, - json_t *json) -{ - json_t *history; - struct TALER_Amount original_value; - struct TALER_Amount melt_value_with_fee; - struct TALER_Amount total; - struct TALER_CoinSpendPublicKeyP coin_pub; - unsigned int i; - struct MAJ_Specification spec[] = { - MAJ_spec_json ("history", &history), - MAJ_spec_fixed_auto ("coin_pub", &coin_pub), - MAJ_spec_amount ("original_value", &original_value), - MAJ_spec_amount ("requested_value", &melt_value_with_fee), - MAJ_spec_end - }; - const struct MeltedCoin *mc; - - /* parse JSON reply */ - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* Find out which coin was deemed problematic by the mint */ - mc = NULL; - for (i=0;i<rmh->md->num_melted_coins;i++) - { - if (0 == TALER_amount_cmp (&melt_value_with_fee, - &rmh->md->melted_coins[i].melt_amount_with_fee)) - { - struct TALER_CoinSpendPublicKeyP mc_pub; - - GNUNET_CRYPTO_eddsa_key_get_public (&rmh->md->melted_coins[i].coin_priv.eddsa_priv, - &mc_pub.eddsa_pub); - if (0 == memcmp (&mc_pub, - &coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))) - { - mc = &rmh->md->melted_coins[i]; - break; - } - } - } - if (NULL == mc) - { - /* coin not found in our original request */ - GNUNET_break_op (0); - json_decref (history); - return GNUNET_SYSERR; - } - - /* check basic coin properties */ - if (0 != TALER_amount_cmp (&original_value, - &mc->original_value)) - { - /* We disagree on the value of the coin */ - GNUNET_break_op (0); - json_decref (history); - return GNUNET_SYSERR; - } - if (0 != TALER_amount_cmp (&melt_value_with_fee, - &mc->melt_amount_with_fee)) - { - /* We disagree on the value of the coin */ - GNUNET_break_op (0); - json_decref (history); - return GNUNET_SYSERR; - } - - /* verify coin history */ - history = json_object_get (json, - "history"); - if (GNUNET_OK != - TALER_MINT_verify_coin_history_ (original_value.currency, - &coin_pub, - history, - &total)) - { - GNUNET_break_op (0); - json_decref (history); - return GNUNET_SYSERR; - } - json_decref (history); - - /* check if melt operation was really too expensive given history */ - if (GNUNET_OK != - TALER_amount_add (&total, - &total, - &melt_value_with_fee)) - { - /* clearly not OK if our transaction would have caused - the overflow... */ - return GNUNET_OK; - } - - if (0 >= TALER_amount_cmp (&total, - &original_value)) - { - /* transaction should have still fit */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - - /* everything OK, valid proof of double-spending was provided */ - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /refresh/melt request. - * - * @param cls the `struct TALER_MINT_RefreshMeltHandle` - * @param eh the curl request handle - */ -static void -handle_refresh_melt_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_RefreshMeltHandle *rmh = cls; - long response_code; - json_t *json; - uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */ - - rmh->job = NULL; - json = MAC_download_get_result (&rmh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - verify_refresh_melt_signature_ok (rmh, - json, - &noreveal_index)) - { - GNUNET_break_op (0); - response_code = 0; - } - if (NULL != rmh->melt_cb) - { - rmh->melt_cb (rmh->melt_cb_cls, - response_code, - noreveal_index, - json); - rmh->melt_cb = NULL; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_FORBIDDEN: - /* Double spending; check signatures on transaction history */ - if (GNUNET_OK != - verify_refresh_melt_signature_forbidden (rmh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint says one of the signatures is - invalid; assuming we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (NULL != rmh->melt_cb) - rmh->melt_cb (rmh->melt_cb_cls, - response_code, - UINT16_MAX, - json); - json_decref (json); - TALER_MINT_refresh_melt_cancel (rmh); -} - - -/** - * Convert a coin to be melted to the respective JSON encoding. - * - * @param melt_session_hash session hash to use - * @param mc coin to be melted - * @return JSON encoding of the melting request - */ -static json_t * -melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash, - const struct MeltedCoin *mc) -{ - struct TALER_CoinSpendSignatureP confirm_sig; - struct TALER_RefreshMeltCoinAffirmationPS melt; - - melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); - melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - melt.session_hash = *melt_session_hash; - TALER_amount_hton (&melt.amount_with_fee, - &mc->melt_amount_with_fee); - TALER_amount_hton (&melt.melt_fee, - &mc->fee_melt); - GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv, - &melt.coin_pub.eddsa_pub); - GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv, - &melt.purpose, - &confirm_sig.eddsa_signature); - return json_pack ("{s:o, s:o, s:o, s:o, s:o}", - "coin_pub", - TALER_json_from_data (&melt.coin_pub, - sizeof (melt.coin_pub)), - "denom_pub", - TALER_json_from_rsa_public_key (mc->pub_key.rsa_public_key), - "denom_sig", - TALER_json_from_rsa_signature (mc->sig.rsa_signature), - "confirm_sig", - TALER_json_from_data (&confirm_sig, - sizeof (confirm_sig)), - "value_with_fee", - TALER_json_from_amount (&mc->melt_amount_with_fee)); -} - - -/** - * Submit a melt request to the mint and get the mint's - * response. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, the provided - * argument should have been constructed using - * #TALER_MINT_refresh_prepare and committed to persistent storage - * prior to calling this function. - * - * @param mint the mint handle; the mint must be ready to operate - * @param refresh_data_length size of the @a refresh_data (returned - * in the `res_size` argument from #TALER_MINT_refresh_prepare()) - * @param refresh_data the refresh data as returned from - #TALER_MINT_refresh_prepare()) - * @param melt_cb the callback to call with the result - * @param melt_cb_cls closure for @a melt_cb - * @return a handle for this request; NULL if the argument was invalid. - * In this case, neither callback will be called. - */ -struct TALER_MINT_RefreshMeltHandle * -TALER_MINT_refresh_melt (struct TALER_MINT_Handle *mint, - size_t refresh_data_length, - const char *refresh_data, - TALER_MINT_RefreshMeltCallback melt_cb, - void *melt_cb_cls) -{ - json_t *melt_obj; - json_t *new_denoms; - json_t *melt_coins; - json_t *coin_evs; - json_t *transfer_pubs; - json_t *secret_encs; - json_t *link_encs; - json_t *tmp; - struct TALER_MINT_RefreshMeltHandle *rmh; - CURL *eh; - struct TALER_MINT_Context *ctx; - struct MeltData *md; - unsigned int i; - unsigned int j; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - md = deserialize_melt_data (refresh_data, - refresh_data_length); - if (NULL == md) - { - GNUNET_break (0); - return NULL; - } - - /* build JSON request, each of the 6 arrays first */ - new_denoms = json_array (); - melt_coins = json_array (); - coin_evs = json_array (); - transfer_pubs = json_array (); - secret_encs = json_array (); - link_encs = json_array (); - for (i=0;i<md->num_melted_coins;i++) - { - const struct MeltedCoin *mc = &md->melted_coins[i]; - - /* now melt_coins */ - json_array_append (melt_coins, - melted_coin_to_json (&md->melt_session_hash, - mc)); - } - - /* now transfer_pubs */ - for (j=0;j<TALER_CNC_KAPPA;j++) - { - tmp = json_array (); - for (i=0;i<md->num_melted_coins;i++) - { - const struct MeltedCoin *mc = &md->melted_coins[i]; - struct TALER_TransferPublicKeyP transfer_pub; - - GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv, - &transfer_pub.ecdhe_pub); - json_array_append (tmp, - TALER_json_from_data (&transfer_pub, - sizeof (transfer_pub))); - } - json_array_append (transfer_pubs, - tmp); - } - - /* now secret_encs */ - for (j=0;j<TALER_CNC_KAPPA;j++) - { - tmp = json_array (); - for (i=0;i<md->num_melted_coins;i++) - { - const struct MeltedCoin *mc = &md->melted_coins[i]; - struct TALER_EncryptedLinkSecretP els; - struct TALER_TransferSecretP trans_sec; - - TALER_link_derive_transfer_secret (&mc->coin_priv, - &mc->transfer_priv[j], - &trans_sec); - GNUNET_assert (GNUNET_OK == - TALER_transfer_encrypt (&md->link_secrets[j], - &trans_sec, - &els)); - json_array_append (tmp, - TALER_json_from_data (&els, - sizeof (els))); - } - json_array_append (secret_encs, - tmp); - } - - /* now new_denoms */ - for (i=0;i<md->num_fresh_coins;i++) - { - json_array_append (new_denoms, - TALER_json_from_rsa_public_key - (md->fresh_pks[i].rsa_public_key)); - } - - /* now link_encs */ - for (j=0;j<TALER_CNC_KAPPA;j++) - { - tmp = json_array (); - for (i=0;i<md->num_fresh_coins;i++) - { - const struct FreshCoin *fc = &md->fresh_coins[j][i]; - struct TALER_RefreshLinkDecrypted rld; - struct TALER_RefreshLinkEncrypted *rle; - char *buf; - size_t buf_len; - - rld.coin_priv = fc->coin_priv; - rld.blinding_key = fc->blinding_key; - rle = TALER_refresh_encrypt (&rld, - &md->link_secrets[j]); - GNUNET_assert (NULL != rle); - buf = TALER_refresh_link_encrypted_encode (rle, - &buf_len); - GNUNET_assert (NULL != buf); - json_array_append (tmp, - TALER_json_from_data (buf, - buf_len)); - GNUNET_free (buf); - GNUNET_free (rle); - } - json_array_append (link_encs, - tmp); - } - - /* now coin_evs */ - for (j=0;j<TALER_CNC_KAPPA;j++) - { - tmp = json_array (); - for (i=0;i<md->num_fresh_coins;i++) - { - const struct FreshCoin *fc = &md->fresh_coins[j][i]; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode coin_hash; - char *coin_ev; /* blinded message to be signed (in envelope) for each coin */ - size_t coin_ev_size; - - GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), - &coin_hash); - coin_ev_size = GNUNET_CRYPTO_rsa_blind (&coin_hash, - fc->blinding_key.rsa_blinding_key, - md->fresh_pks[i].rsa_public_key, - &coin_ev); - json_array_append (tmp, - TALER_json_from_data (coin_ev, - coin_ev_size)); - GNUNET_free (coin_ev); - } - json_array_append (coin_evs, - tmp); - } - - /* finally, assemble main JSON request from constitutent arrays */ - melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", - "new_denoms", new_denoms, - "melt_coins", melt_coins, - "coin_evs", coin_evs, - "transfer_pubs", transfer_pubs, - "secret_encs", secret_encs, - "link_encs", link_encs); - - /* and now we can at last begin the actual request handling */ - rmh = GNUNET_new (struct TALER_MINT_RefreshMeltHandle); - rmh->mint = mint; - rmh->melt_cb = melt_cb; - rmh->melt_cb_cls = melt_cb_cls; - rmh->md = md; - rmh->url = MAH_path_to_url (mint, - "/refresh/melt"); - - eh = curl_easy_init (); - GNUNET_assert (NULL != (rmh->json_enc = - json_dumps (melt_obj, - JSON_COMPACT))); - json_decref (melt_obj); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - rmh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - rmh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (rmh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &rmh->db)); - ctx = MAH_handle_to_context (mint); - rmh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_refresh_melt_finished, - rmh); - return rmh; -} - - -/** - * Cancel a refresh execute request. This function cannot be used - * on a request handle if either callback was already invoked. - * - * @param rmh the refresh melt handle - */ -void -TALER_MINT_refresh_melt_cancel (struct TALER_MINT_RefreshMeltHandle *rmh) -{ - if (NULL != rmh->job) - { - MAC_job_cancel (rmh->job); - rmh->job = NULL; - } - GNUNET_free_non_null (rmh->db.buf); - free_melt_data (rmh->md); /* does not free 'md' itself */ - GNUNET_free (rmh->md); - GNUNET_free (rmh->url); - GNUNET_free (rmh->json_enc); - GNUNET_free (rmh); -} - - -/* ********************* /refresh/reveal ***************************** */ - - -/** - * @brief A /refresh/reveal Handle - */ -struct TALER_MINT_RefreshRevealHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_RefreshRevealCallback reveal_cb; - - /** - * Closure for @e reveal_cb. - */ - void *reveal_cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Actual information about the melt operation. - */ - struct MeltData *md; - - /** - * The index selected by the mint in cut-and-choose to not be revealed. - */ - uint16_t noreveal_index; - -}; - - -/** - * We got a 200 OK response for the /refresh/reveal operation. - * Extract the coin signatures and return them to the caller. - * The signatures we get from the mint is for the blinded value. - * Thus, we first must unblind them and then should verify their - * validity. - * - * If everything checks out, we return the unblinded signatures - * to the application via the callback. - * - * @param rrh operation handle - * @param json reply from the mint - * @param[out] coin_privs array of length `num_fresh_coins`, initialized to contain private keys - * @param[out] sigs array of length `num_fresh_coins`, initialized to cointain RSA signatures - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static int -refresh_reveal_ok (struct TALER_MINT_RefreshRevealHandle *rrh, - json_t *json, - struct TALER_CoinSpendPrivateKeyP *coin_privs, - struct TALER_DenominationSignature *sigs) -{ - unsigned int i; - json_t *jsona; - struct MAJ_Specification spec[] = { - MAJ_spec_json ("ev_sigs", &jsona), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (! json_is_array (jsona)) - { - /* We expected an array of coins */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (rrh->md->num_fresh_coins != json_array_size (jsona)) - { - /* Number of coins generated does not match our expectation */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - for (i=0;i<rrh->md->num_fresh_coins;i++) - { - const struct FreshCoin *fc; - struct TALER_DenominationPublicKey *pk; - json_t *jsonai; - struct GNUNET_CRYPTO_rsa_Signature *blind_sig; - struct GNUNET_CRYPTO_rsa_Signature *sig; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode coin_hash; - - struct MAJ_Specification spec[] = { - MAJ_spec_rsa_signature ("ev_sig", &blind_sig), - MAJ_spec_end - }; - - fc = &rrh->md->fresh_coins[rrh->noreveal_index][i]; - pk = &rrh->md->fresh_pks[i]; - jsonai = json_array_get (jsona, i); - GNUNET_assert (NULL != jsonai); - - if (GNUNET_OK != - MAJ_parse_json (jsonai, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* unblind the signature */ - sig = GNUNET_CRYPTO_rsa_unblind (blind_sig, - fc->blinding_key.rsa_blinding_key, - pk->rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (blind_sig); - - /* verify the signature */ - GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), - &coin_hash); - - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (&coin_hash, - sig, - pk->rsa_public_key)) - { - GNUNET_break_op (0); - GNUNET_CRYPTO_rsa_signature_free (sig); - return GNUNET_SYSERR; - } - coin_privs[i] = fc->coin_priv; - sigs[i].rsa_signature = sig; - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /refresh/reveal request. - * - * @param cls the `struct TALER_MINT_RefreshHandle` - * @param eh the curl request handle - */ -static void -handle_refresh_reveal_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_RefreshRevealHandle *rrh = cls; - long response_code; - json_t *json; - - rrh->job = NULL; - json = MAC_download_get_result (&rrh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins]; - struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins]; - unsigned int i; - int ret; - - memset (sigs, 0, sizeof (sigs)); - ret = refresh_reveal_ok (rrh, - json, - coin_privs, - sigs); - if (GNUNET_OK != ret) - { - response_code = 0; - } - else - { - rrh->reveal_cb (rrh->reveal_cb_cls, - MHD_HTTP_OK, - rrh->md->num_fresh_coins, - coin_privs, - sigs, - json); - rrh->reveal_cb = NULL; - } - for (i=0;i<rrh->md->num_fresh_coins;i++) - if (NULL != sigs[i].rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature); - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_CONFLICT: - /* Nothing really to verify, mint says our reveal is inconsitent - with our commitment, so either side is buggy; we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (NULL != rrh->reveal_cb) - rrh->reveal_cb (rrh->reveal_cb_cls, - response_code, - 0, NULL, NULL, - json); - json_decref (json); - TALER_MINT_refresh_reveal_cancel (rrh); -} - - -/** - * Submit a /refresh/reval request to the mint and get the mint's - * response. - * - * This API is typically used by a wallet. Note that to ensure that - * no money is lost in case of hardware failures, the provided - * arguments should have been committed to persistent storage - * prior to calling this function. - * - * @param mint the mint handle; the mint must be ready to operate - * @param refresh_data_length size of the @a refresh_data (returned - * in the `res_size` argument from #TALER_MINT_refresh_prepare()) - * @param refresh_data the refresh data as returned from - #TALER_MINT_refresh_prepare()) - * @param noreveal_index response from the mint to the - * #TALER_MINT_refresh_melt() invocation - * @param reveal_cb the callback to call with the final result of the - * refresh operation - * @param reveal_cb_cls closure for the above callback - * @return a handle for this request; NULL if the argument was invalid. - * In this case, neither callback will be called. - */ -struct TALER_MINT_RefreshRevealHandle * -TALER_MINT_refresh_reveal (struct TALER_MINT_Handle *mint, - size_t refresh_data_length, - const char *refresh_data, - uint16_t noreveal_index, - TALER_MINT_RefreshRevealCallback reveal_cb, - void *reveal_cb_cls) -{ - struct TALER_MINT_RefreshRevealHandle *rrh; - json_t *transfer_privs; - json_t *reveal_obj; - json_t *tmp; - CURL *eh; - struct TALER_MINT_Context *ctx; - struct MeltData *md; - unsigned int i; - unsigned int j; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - md = deserialize_melt_data (refresh_data, - refresh_data_length); - if (NULL == md) - { - GNUNET_break (0); - return NULL; - } - if (noreveal_index >= TALER_CNC_KAPPA) - { - /* We check this here, as it would be really bad to below just - disclose all the transfer keys. Note that this error should - have been caught way earlier when the mint replied, but maybe - we had some internal corruption that changed the value... */ - GNUNET_break (0); - return NULL; - } - - /* build array of transfer private keys */ - transfer_privs = json_array (); - for (j=0;j<TALER_CNC_KAPPA;j++) - { - if (j == noreveal_index) - { - /* This is crucial: exclude the transfer key for the - noreval index! */ - continue; - } - tmp = json_array (); - for (i=0;i<md->num_melted_coins;i++) - { - const struct MeltedCoin *mc = &md->melted_coins[i]; - - json_array_append (tmp, - TALER_json_from_data (&mc->transfer_priv[j], - sizeof (struct TALER_TransferPrivateKeyP))); - } - json_array_append (transfer_privs, - tmp); - } - - /* build main JSON request */ - reveal_obj = json_pack ("{s:o, s:o}", - "session_hash", - TALER_json_from_data (&md->melt_session_hash, - sizeof (struct GNUNET_HashCode)), - "transfer_privs", - transfer_privs); - - /* finally, we can actually issue the request */ - rrh = GNUNET_new (struct TALER_MINT_RefreshRevealHandle); - rrh->mint = mint; - rrh->noreveal_index = noreveal_index; - rrh->reveal_cb = reveal_cb; - rrh->reveal_cb_cls = reveal_cb_cls; - rrh->md = md; - rrh->url = MAH_path_to_url (rrh->mint, - "/refresh/reveal"); - - eh = curl_easy_init (); - GNUNET_assert (NULL != (rrh->json_enc = - json_dumps (reveal_obj, - JSON_COMPACT))); - json_decref (reveal_obj); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - rrh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - rrh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (rrh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &rrh->db)); - ctx = MAH_handle_to_context (rrh->mint); - rrh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_refresh_reveal_finished, - rrh); - return rrh; -} - - -/** - * Cancel a refresh reveal request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param rrh the refresh reval handle - */ -void -TALER_MINT_refresh_reveal_cancel (struct TALER_MINT_RefreshRevealHandle *rrh) -{ - if (NULL != rrh->job) - { - MAC_job_cancel (rrh->job); - rrh->job = NULL; - } - GNUNET_free_non_null (rrh->db.buf); - GNUNET_free (rrh->url); - GNUNET_free (rrh->json_enc); - free_melt_data (rrh->md); /* does not free 'md' itself */ - GNUNET_free (rrh->md); - GNUNET_free (rrh); -} - - -/* end of mint_api_refresh.c */ diff --git a/src/mint-lib/mint_api_refresh_link.c b/src/mint-lib/mint_api_refresh_link.c deleted file mode 100644 index dcd2326ca..000000000 --- a/src/mint-lib/mint_api_refresh_link.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_refresh_link.c - * @brief Implementation of the /refresh/link request of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A /refresh/link Handle - */ -struct TALER_MINT_RefreshLinkHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_RefreshLinkCallback link_cb; - - /** - * Closure for @e cb. - */ - void *link_cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Private key of the coin, required to decode link information. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - -}; - - -/** - * Parse the provided linkage data from the "200 OK" response - * for one of the coins. - * - * @param rlh refresh link handle - * @param json json reply with the data for one coin - * @param trans_pub our transfer public key - * @param secret_enc encrypted key to decrypt link data - * @param[out] coin_priv where to return private coin key - * @param[out] sig where to return private coin signature - * @param[out] pub where to return the public key for the coin - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -parse_refresh_link_coin (const struct TALER_MINT_RefreshLinkHandle *rlh, - json_t *json, - const struct TALER_TransferPublicKeyP *trans_pub, - const struct TALER_EncryptedLinkSecretP *secret_enc, - struct TALER_CoinSpendPrivateKeyP *coin_priv, - struct TALER_DenominationSignature *sig, - struct TALER_DenominationPublicKey *pub) -{ - void *link_enc; - size_t link_enc_size; - struct GNUNET_CRYPTO_rsa_Signature *bsig; - struct GNUNET_CRYPTO_rsa_PublicKey *rpub; - struct MAJ_Specification spec[] = { - MAJ_spec_varsize ("link_enc", &link_enc, &link_enc_size), - MAJ_spec_rsa_public_key ("denom_pub", &rpub), - MAJ_spec_rsa_signature ("ev_sig", &bsig), - MAJ_spec_end - }; - struct TALER_RefreshLinkEncrypted *rle; - struct TALER_RefreshLinkDecrypted *rld; - struct TALER_LinkSecretP secret; - - /* parse reply */ - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* decode and decrypt link data */ - rle = TALER_refresh_link_encrypted_decode (link_enc, - link_enc_size); - if (NULL == rle) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_link_decrypt_secret2 (secret_enc, - trans_pub, - &rlh->coin_priv, - &secret)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - rld = TALER_refresh_decrypt (rle, - &secret); - if (NULL == rld) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - - /* extract coin and signature */ - *coin_priv = rld->coin_priv; - sig->rsa_signature - = GNUNET_CRYPTO_rsa_unblind (bsig, - rld->blinding_key.rsa_blinding_key, - rpub); - - /* clean up */ - GNUNET_free (rld); - pub->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (rpub); - MAJ_parse_free (spec); - return GNUNET_OK; -} - - -/** - * Parse the provided linkage data from the "200 OK" response - * for one of the coins. - * - * @param[in,out] rlh refresh link handle (callback may be zero'ed out) - * @param json json reply with the data for one coin - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh, - json_t *json) -{ - unsigned int session; - unsigned int num_coins; - int ret; - - if (! json_is_array (json)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - num_coins = 0; - /* Theoretically, a coin may have been melted repeatedly - into different sessions; so the response is an array - which contains information by melting session. That - array contains another array. However, our API returns - a single 1d array, so we flatten the 2d array that is - returned into a single array. Note that usually a coin - is melted at most once, and so we'll only run this - loop once for 'session=0' in most cases. - - num_coins tracks the size of the 1d array we return, - whilst 'i' and 'session' track the 2d array. */ - for (session=0;session<json_array_size (json); session++) - { - json_t *jsona; - struct MAJ_Specification spec[] = { - MAJ_spec_json ("new_coins", &jsona), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json_array_get (json, - session), - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (! json_is_array (jsona)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - - /* count all coins over all sessions */ - num_coins += json_array_size (jsona); - MAJ_parse_free (spec); - } - /* Now that we know how big the 1d array is, allocate - and fill it. */ - { - unsigned int off_coin; /* index into 1d array */ - unsigned int i; - struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins]; - struct TALER_DenominationSignature sigs[num_coins]; - struct TALER_DenominationPublicKey pubs[num_coins]; - - memset (sigs, 0, sizeof (sigs)); - memset (pubs, 0, sizeof (pubs)); - off_coin = 0; - for (session=0;session<json_array_size (json); session++) - { - json_t *jsona; - struct TALER_TransferPublicKeyP trans_pub; - struct TALER_EncryptedLinkSecretP secret_enc; - struct MAJ_Specification spec[] = { - MAJ_spec_json ("new_coins", &jsona), - MAJ_spec_fixed_auto ("transfer_pub", &trans_pub), - MAJ_spec_fixed_auto ("secret_enc", &secret_enc), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json_array_get (json, - session), - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (! json_is_array (jsona)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - - /* decode all coins */ - for (i=0;i<json_array_size (jsona);i++) - { - if (GNUNET_OK != - parse_refresh_link_coin (rlh, - json_array_get (jsona, - i), - &trans_pub, - &secret_enc, - &coin_privs[i+off_coin], - &sigs[i+off_coin], - &pubs[i+off_coin])) - { - GNUNET_break_op (0); - break; - } - } - /* check if we really got all, then invoke callback */ - off_coin += i; - if (i != json_array_size (jsona)) - { - GNUNET_break_op (0); - ret = GNUNET_SYSERR; - MAJ_parse_free (spec); - break; - } - MAJ_parse_free (spec); - } /* end of for (session) */ - - if (off_coin == num_coins) - { - rlh->link_cb (rlh->link_cb_cls, - MHD_HTTP_OK, - num_coins, - coin_privs, - sigs, - pubs, - json); - rlh->link_cb = NULL; - ret = GNUNET_OK; - } - else - { - GNUNET_break_op (0); - ret = GNUNET_SYSERR; - } - - /* clean up */ - for (i=0;i<off_coin;i++) - { - if (NULL != sigs[i].rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature); - if (NULL != pubs[i].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key); - } - } - return ret; -} - - -/** - * Function called when we're done processing the - * HTTP /refresh/link request. - * - * @param cls the `struct TALER_MINT_RefreshLinkHandle` - * @param eh the curl request handle - */ -static void -handle_refresh_link_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_RefreshLinkHandle *rlh = cls; - long response_code; - json_t *json; - - rlh->job = NULL; - json = MAC_download_get_result (&rlh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - parse_refresh_link_ok (rlh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, mint says this coin was not melted; we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (NULL != rlh->link_cb) - rlh->link_cb (rlh->link_cb_cls, - response_code, - 0, NULL, NULL, NULL, - json); - json_decref (json); - TALER_MINT_refresh_link_cancel (rlh); -} - - -/** - * Submit a link request to the mint and get the mint's response. - * - * This API is typically not used by anyone, it is more a threat - * against those trying to receive a funds transfer by abusing the - * /refresh protocol. - * - * @param mint the mint handle; the mint must be ready to operate - * @param coin_priv private key to request link data for - * @param link_cb the callback to call with the useful result of the - * refresh operation the @a coin_priv was involved in (if any) - * @param link_cb_cls closure for @a link_cb - * @return a handle for this request - */ -struct TALER_MINT_RefreshLinkHandle * -TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - TALER_MINT_RefreshLinkCallback link_cb, - void *link_cb_cls) -{ - struct TALER_MINT_RefreshLinkHandle *rlh; - CURL *eh; - struct TALER_MINT_Context *ctx; - struct TALER_CoinSpendPublicKeyP coin_pub; - char *pub_str; - char *arg_str; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - pub_str = GNUNET_STRINGS_data_to_string_alloc (&coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - GNUNET_asprintf (&arg_str, - "/refresh/link?coin_pub=%s", - pub_str); - GNUNET_free (pub_str); - - rlh = GNUNET_new (struct TALER_MINT_RefreshLinkHandle); - rlh->mint = mint; - rlh->link_cb = link_cb; - rlh->link_cb_cls = link_cb_cls; - rlh->coin_priv = *coin_priv; - rlh->url = MAH_path_to_url (mint, arg_str); - GNUNET_free (arg_str); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - rlh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &rlh->db)); - ctx = MAH_handle_to_context (mint); - rlh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_refresh_link_finished, - rlh); - return rlh; -} - - -/** - * Cancel a refresh link request. This function cannot be used - * on a request handle if the callback was already invoked. - * - * @param rlh the refresh link handle - */ -void -TALER_MINT_refresh_link_cancel (struct TALER_MINT_RefreshLinkHandle *rlh) -{ - if (NULL != rlh->job) - { - MAC_job_cancel (rlh->job); - rlh->job = NULL; - } - GNUNET_free_non_null (rlh->db.buf); - GNUNET_free (rlh->url); - GNUNET_free (rlh); -} - - -/* end of mint_api_refresh_link.c */ diff --git a/src/mint-lib/mint_api_reserve.c b/src/mint-lib/mint_api_reserve.c deleted file mode 100644 index 1f8140cff..000000000 --- a/src/mint-lib/mint_api_reserve.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_reserve.c - * @brief Implementation of the /reserve requests of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/* ********************** /reserve/status ********************** */ - -/** - * @brief A Withdraw Status Handle - */ -struct TALER_MINT_ReserveStatusHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_ReserveStatusResultCallback cb; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - -}; - - -/** - * Parse history given in JSON format and return it in binary - * format. - * - * @param[in] history JSON array with the history - * @param reserve_pub public key of the reserve to inspect - * @param currency currency we expect the balance to be in - * @param[out] balance final balance - * @param history_length number of entries in @a history - * @param[out] rhistory array of length @a history_length, set to the - * parsed history entries - * @return #GNUNET_OK if history was valid and @a rhistory and @a balance - * were set, - * #GNUNET_SYSERR if there was a protocol violation in @a history - */ -static int -parse_reserve_history (json_t *history, - const struct TALER_ReservePublicKeyP *reserve_pub, - const char *currency, - struct TALER_Amount *balance, - unsigned int history_length, - struct TALER_MINT_ReserveHistory *rhistory) -{ - struct GNUNET_HashCode uuid[history_length]; - unsigned int uuid_off; - struct TALER_Amount total_in; - struct TALER_Amount total_out; - size_t off; - - TALER_amount_get_zero (currency, - &total_in); - TALER_amount_get_zero (currency, - &total_out); - uuid_off = 0; - for (off=0;off<history_length;off++) - { - json_t *transaction; - struct TALER_Amount amount; - const char *type; - struct MAJ_Specification hist_spec[] = { - MAJ_spec_string ("type", &type), - MAJ_spec_amount ("amount", - &amount), - /* 'wire' and 'signature' are optional depending on 'type'! */ - MAJ_spec_end - }; - - transaction = json_array_get (history, - off); - if (GNUNET_OK != - MAJ_parse_json (transaction, - hist_spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - rhistory[off].amount = amount; - - if (0 == strcasecmp (type, - "DEPOSIT")) - { - json_t *wire; - - rhistory[off].type = TALER_MINT_RTT_DEPOSIT; - if (GNUNET_OK != - TALER_amount_add (&total_in, - &total_in, - &amount)) - { - /* overflow in history already!? inconceivable! Bad mint! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - wire = json_object_get (transaction, - "wire"); - /* check 'wire' is a JSON object (no need to check wireformat, - but we do at least expect "some" JSON object here) */ - if ( (NULL == wire) || - (! json_is_object (wire)) ) - { - /* not even a JSON 'wire' specification, not acceptable */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - rhistory[off].details.wire_in_details = wire; - /* end type==DEPOSIT */ - } - else if (0 == strcasecmp (type, - "WITHDRAW")) - { - struct TALER_ReserveSignatureP sig; - struct TALER_WithdrawRequestPS withdraw_purpose; - struct TALER_Amount amount_from_purpose; - struct MAJ_Specification withdraw_spec[] = { - MAJ_spec_fixed_auto ("signature", - &sig), - MAJ_spec_fixed_auto ("details", - &withdraw_purpose), - MAJ_spec_end - }; - unsigned int i; - - rhistory[off].type = TALER_MINT_RTT_WITHDRAWAL; - if (GNUNET_OK != - MAJ_parse_json (transaction, - withdraw_spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* Check that the signature is a valid withdraw request */ - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, - &withdraw_purpose.purpose, - &sig.eddsa_signature, - &reserve_pub->eddsa_pub)) - { - GNUNET_break_op (0); - MAJ_parse_free (withdraw_spec); - return GNUNET_SYSERR; - } - TALER_amount_ntoh (&amount_from_purpose, - &withdraw_purpose.amount_with_fee); - if (0 != TALER_amount_cmp (&amount, - &amount_from_purpose)) - { - GNUNET_break_op (0); - MAJ_parse_free (withdraw_spec); - return GNUNET_SYSERR; - } - rhistory[off].details.out_authorization_sig = json_object_get (transaction, - "signature"); - /* Check check that the same withdraw transaction - isn't listed twice by the mint. We use the - "uuid" array to remember the hashes of all - purposes, and compare the hashes to find - duplicates. */ - GNUNET_CRYPTO_hash (&withdraw_purpose, - ntohl (withdraw_purpose.purpose.size), - &uuid[uuid_off]); - for (i=0;i<uuid_off;i++) - { - if (0 == memcmp (&uuid[uuid_off], - &uuid[i], - sizeof (struct GNUNET_HashCode))) - { - GNUNET_break_op (0); - MAJ_parse_free (withdraw_spec); - return GNUNET_SYSERR; - } - } - uuid_off++; - - if (GNUNET_OK != - TALER_amount_add (&total_out, - &total_out, - &amount)) - { - /* overflow in history already!? inconceivable! Bad mint! */ - GNUNET_break_op (0); - MAJ_parse_free (withdraw_spec); - return GNUNET_SYSERR; - } - /* end type==WITHDRAW */ - } - else - { - /* unexpected 'type', protocol incompatibility, complain! */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - - /* check balance = total_in - total_out < withdraw-amount */ - if (GNUNET_SYSERR == - TALER_amount_subtract (balance, - &total_in, - &total_out)) - { - /* total_in < total_out, why did the mint ever allow this!? */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserve/status request. - * - * @param cls the `struct TALER_MINT_ReserveStatusHandle` - * @param eh curl handle of the request that finished - */ -static void -handle_reserve_status_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_ReserveStatusHandle *wsh = cls; - long response_code; - json_t *json; - - wsh->job = NULL; - json = MAC_download_get_result (&wsh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - /* TODO: move into separate function... */ - json_t *history; - unsigned int len; - struct TALER_Amount balance; - struct TALER_Amount balance_from_history; - struct MAJ_Specification spec[] = { - MAJ_spec_amount ("balance", &balance), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - history = json_object_get (json, - "history"); - if (NULL == history) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - len = json_array_size (history); - { - struct TALER_MINT_ReserveHistory rhistory[len]; - - if (GNUNET_OK != - parse_reserve_history (history, - &wsh->reserve_pub, - balance.currency, - &balance_from_history, - len, - rhistory)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - if (0 != - TALER_amount_cmp (&balance_from_history, - &balance)) - { - /* mint cannot add up balances!? */ - GNUNET_break_op (0); - response_code = 0; - break; - } - wsh->cb (wsh->cb_cls, - response_code, - json, - &balance, - len, - rhistory); - wsh->cb = NULL; - } - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (NULL != wsh->cb) - wsh->cb (wsh->cb_cls, - response_code, - json, - NULL, - 0, NULL); - json_decref (json); - TALER_MINT_reserve_status_cancel (wsh); -} - - -/** - * Submit a request to obtain the transaction history of a reserve - * from the mint. Note that while we return the full response to the - * caller for further processing, we do already verify that the - * response is well-formed (i.e. that signatures included in the - * response are all valid and add up to the balance). If the mint's - * reply is not well-formed, we return an HTTP status code of zero to - * @a cb. - * - * @param mint the mint handle; the mint must be ready to operate - * @param reserve_pub public key of the reserve to inspect - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_MINT_ReserveStatusHandle * -TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint, - const struct TALER_ReservePublicKeyP *reserve_pub, - TALER_MINT_ReserveStatusResultCallback cb, - void *cb_cls) -{ - struct TALER_MINT_ReserveStatusHandle *wsh; - struct TALER_MINT_Context *ctx; - CURL *eh; - char *pub_str; - char *arg_str; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub, - sizeof (struct TALER_ReservePublicKeyP)); - GNUNET_asprintf (&arg_str, - "/reserve/status?reserve_pub=%s", - pub_str); - GNUNET_free (pub_str); - wsh = GNUNET_new (struct TALER_MINT_ReserveStatusHandle); - wsh->mint = mint; - wsh->cb = cb; - wsh->cb_cls = cb_cls; - wsh->reserve_pub = *reserve_pub; - wsh->url = MAH_path_to_url (mint, - arg_str); - GNUNET_free (arg_str); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wsh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wsh->db)); - ctx = MAH_handle_to_context (mint); - wsh->job = MAC_job_add (ctx, - eh, - GNUNET_NO, - &handle_reserve_status_finished, - wsh); - return wsh; -} - - -/** - * Cancel a withdraw status request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param wsh the withdraw status request handle - */ -void -TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh) -{ - if (NULL != wsh->job) - { - MAC_job_cancel (wsh->job); - wsh->job = NULL; - } - GNUNET_free_non_null (wsh->db.buf); - GNUNET_free (wsh->url); - GNUNET_free (wsh); -} - - -/* ********************** /reserve/withdraw ********************** */ - -/** - * @brief A Withdraw Sign Handle - */ -struct TALER_MINT_ReserveWithdrawHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_ReserveWithdrawResultCallback cb; - - /** - * Key used to blind the value. - */ - const struct TALER_DenominationBlindingKey *blinding_key; - - /** - * Denomination key we are withdrawing. - */ - const struct TALER_MINT_DenomPublicKey *pk; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Hash of the public key of the coin we are signing. - */ - struct GNUNET_HashCode c_hash; - - /** - * Public key of the reserve we are withdrawing from. - */ - struct TALER_ReservePublicKeyP reserve_pub; - -}; - - -/** - * We got a 200 OK response for the /reserve/withdraw operation. - * Extract the coin's signature and return it to the caller. - * The signature we get from the mint is for the blinded value. - * Thus, we first must unblind it and then should verify its - * validity against our coin's hash. - * - * If everything checks out, we return the unblinded signature - * to the application via the callback. - * - * @param wsh operation handle - * @param json reply from the mint - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static int -reserve_withdraw_ok (struct TALER_MINT_ReserveWithdrawHandle *wsh, - json_t *json) -{ - struct GNUNET_CRYPTO_rsa_Signature *blind_sig; - struct GNUNET_CRYPTO_rsa_Signature *sig; - struct TALER_DenominationSignature dsig; - struct MAJ_Specification spec[] = { - MAJ_spec_rsa_signature ("ev_sig", &blind_sig), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - sig = GNUNET_CRYPTO_rsa_unblind (blind_sig, - wsh->blinding_key->rsa_blinding_key, - wsh->pk->key.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (blind_sig); - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (&wsh->c_hash, - sig, - wsh->pk->key.rsa_public_key)) - { - GNUNET_break_op (0); - GNUNET_CRYPTO_rsa_signature_free (sig); - return GNUNET_SYSERR; - } - /* signature is valid, return it to the application */ - dsig.rsa_signature = sig; - wsh->cb (wsh->cb_cls, - MHD_HTTP_OK, - &dsig, - json); - /* make sure callback isn't called again after return */ - wsh->cb = NULL; - GNUNET_CRYPTO_rsa_signature_free (sig); - return GNUNET_OK; -} - - -/** - * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation. - * Check the signatures on the withdraw transactions in the provided - * history and that the balances add up. We don't do anything directly - * with the information, as the JSON will be returned to the application. - * However, our job is ensuring that the mint followed the protocol, and - * this in particular means checking all of the signatures in the history. - * - * @param wsh operation handle - * @param json reply from the mint - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static int -reserve_withdraw_payment_required (struct TALER_MINT_ReserveWithdrawHandle *wsh, - json_t *json) -{ - struct TALER_Amount balance; - struct TALER_Amount balance_from_history; - struct TALER_Amount requested_amount; - json_t *history; - size_t len; - struct MAJ_Specification spec[] = { - MAJ_spec_amount ("balance", &balance), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - history = json_object_get (json, - "history"); - if (NULL == history) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* go over transaction history and compute - total incoming and outgoing amounts */ - len = json_array_size (history); - { - struct TALER_MINT_ReserveHistory rhistory[len]; - - if (GNUNET_OK != - parse_reserve_history (history, - &wsh->reserve_pub, - balance.currency, - &balance_from_history, - len, - rhistory)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - } - - if (0 != - TALER_amount_cmp (&balance_from_history, - &balance)) - { - /* mint cannot add up balances!? */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* Compute how much we expected to charge to the reserve */ - if (GNUNET_OK != - TALER_amount_add (&requested_amount, - &wsh->pk->value, - &wsh->pk->fee_withdraw)) - { - /* Overflow here? Very strange, our CPU must be fried... */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* Check that funds were really insufficient */ - if (0 >= TALER_amount_cmp (&requested_amount, - &balance)) - { - /* Requested amount is smaller or equal to reported balance, - so this should not have failed. */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserve/withdraw request. - * - * @param cls the `struct TALER_MINT_ReserveWithdrawHandle` - * @param eh curl handle of the request that finished - */ -static void -handle_reserve_withdraw_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_ReserveWithdrawHandle *wsh = cls; - long response_code; - json_t *json; - - wsh->job = NULL; - json = MAC_download_get_result (&wsh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - reserve_withdraw_ok (wsh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_PAYMENT_REQUIRED: - /* The mint says that the reserve has insufficient funds; - check the signatures in the history... */ - if (GNUNET_OK != - reserve_withdraw_payment_required (wsh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_UNAUTHORIZED: - GNUNET_break (0); - /* Nothing really to verify, mint says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, the mint basically just says - that it doesn't know this reserve. Can happen if we - query before the wire transfer went through. - We should simply pass the JSON reply to the application. */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (NULL != wsh->cb) - wsh->cb (wsh->cb_cls, - response_code, - NULL, - json); - json_decref (json); - TALER_MINT_reserve_withdraw_cancel (wsh); -} - - -/** - * Withdraw a coin from the mint using a /reserve/withdraw request. Note - * that to ensure that no money is lost in case of hardware failures, - * the caller must have committed (most of) the arguments to disk - * before calling, and be ready to repeat the request with the same - * arguments in case of failures. - * - * @param mint the mint handle; the mint must be ready to operate - * @param pk kind of coin to create - * @param reserve_priv private key of the reserve to withdraw from - * @param coin_priv where to store the coin's private key, - * caller must have committed this value to disk before the call (with @a pk) - * @param blinding_key where to store the coin's blinding key - * caller must have committed this value to disk before the call (with @a pk) - * @param res_cb the callback to call when the final result for this request is available - * @param res_cb_cls closure for the above callback - * @return #GNUNET_OK on success, #GNUNET_SYSERR - * if the inputs are invalid (i.e. denomination key not with this mint). - * In this case, the callback is not called. - */ -struct TALER_MINT_ReserveWithdrawHandle * -TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint, - const struct TALER_MINT_DenomPublicKey *pk, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct TALER_CoinSpendPrivateKeyP *coin_priv, - const struct TALER_DenominationBlindingKey *blinding_key, - TALER_MINT_ReserveWithdrawResultCallback res_cb, - void *res_cb_cls) -{ - struct TALER_MINT_ReserveWithdrawHandle *wsh; - struct TALER_WithdrawRequestPS req; - struct TALER_ReserveSignatureP reserve_sig; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_MINT_Context *ctx; - struct TALER_Amount amount_with_fee; - char *coin_ev; - size_t coin_ev_size; - json_t *withdraw_obj; - CURL *eh; - - wsh = GNUNET_new (struct TALER_MINT_ReserveWithdrawHandle); - wsh->mint = mint; - wsh->cb = res_cb; - wsh->cb_cls = res_cb_cls; - wsh->pk = pk; - - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), - &wsh->c_hash); - coin_ev_size = GNUNET_CRYPTO_rsa_blind (&wsh->c_hash, - blinding_key->rsa_blinding_key, - pk->key.rsa_public_key, - &coin_ev); - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &wsh->reserve_pub.eddsa_pub); - req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - req.reserve_pub = wsh->reserve_pub; - if (GNUNET_OK != - TALER_amount_add (&amount_with_fee, - &pk->fee_withdraw, - &pk->value)) - { - /* mint gave us denomination keys that overflow like this!? */ - GNUNET_break_op (0); - GNUNET_free (coin_ev); - GNUNET_free (wsh); - return NULL; - } - TALER_amount_hton (&req.amount_with_fee, - &amount_with_fee); - TALER_amount_hton (&req.withdraw_fee, - &pk->fee_withdraw); - GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key, - &req.h_denomination_pub); - GNUNET_CRYPTO_hash (coin_ev, - coin_ev_size, - &req.h_coin_envelope); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, - &req.purpose, - &reserve_sig.eddsa_signature)); - withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */ - " s:o, s:o}",/* reserve_pub and reserve_sig */ - "denom_pub", TALER_json_from_rsa_public_key (pk->key.rsa_public_key), - "coin_ev", TALER_json_from_data (coin_ev, - coin_ev_size), - "reserve_pub", TALER_json_from_data (&wsh->reserve_pub, - sizeof (struct TALER_ReservePublicKeyP)), - "reserve_sig", TALER_json_from_data (&reserve_sig, - sizeof (reserve_sig))); - GNUNET_free (coin_ev); - - wsh->blinding_key = blinding_key; - wsh->url = MAH_path_to_url (mint, "/reserve/withdraw"); - - eh = curl_easy_init (); - GNUNET_assert (NULL != (wsh->json_enc = - json_dumps (withdraw_obj, - JSON_COMPACT))); - json_decref (withdraw_obj); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wsh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - wsh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (wsh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wsh->db)); - ctx = MAH_handle_to_context (mint); - wsh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_reserve_withdraw_finished, - wsh); - return wsh; -} - - -/** - * Cancel a withdraw status request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param sign the withdraw sign request handle - */ -void -TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign) -{ - if (NULL != sign->job) - { - MAC_job_cancel (sign->job); - sign->job = NULL; - } - GNUNET_free_non_null (sign->db.buf); - GNUNET_free (sign->url); - GNUNET_free (sign->json_enc); - GNUNET_free (sign); -} - - -/* end of mint_api_reserve.c */ diff --git a/src/mint-lib/mint_api_wire.c b/src/mint-lib/mint_api_wire.c deleted file mode 100644 index 0947354ad..000000000 --- a/src/mint-lib/mint_api_wire.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_wire.c - * @brief Implementation of the /wire request of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A Wire Handle - */ -struct TALER_MINT_WireHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_WireResultCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Set to the "methods" JSON array returned by the - * /wire request. - */ - json_t *methods; - - /** - * Current iteration offset in the @e methods array. - */ - unsigned int methods_off; - -}; - - -/** - * Verify that the signature on the "200 OK" response - * for /wire/sepa from the mint is valid. - * - * @param wh wire handle - * @param json json reply with the signature - * @return #GNUNET_SYSERR if @a json is invalid, - * #GNUNET_NO if the method is unknown, - * #GNUNET_OK if the json is valid - */ -static int -verify_wire_sepa_signature_ok (const struct TALER_MINT_WireHandle *wh, - json_t *json) -{ - struct TALER_MasterSignatureP mint_sig; - struct TALER_MasterWireSepaDetailsPS mp; - const char *receiver_name; - const char *iban; - const char *bic; - const struct TALER_MINT_Keys *key_state; - struct GNUNET_HashContext *hc; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("sig", &mint_sig), - MAJ_spec_string ("receiver_name", &receiver_name), - MAJ_spec_string ("iban", &iban), - MAJ_spec_string ("bic", &bic), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - key_state = TALER_MINT_get_keys (wh->mint); - mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); - mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS)); - hc = GNUNET_CRYPTO_hash_context_start (); - GNUNET_CRYPTO_hash_context_read (hc, - receiver_name, - strlen (receiver_name) + 1); - GNUNET_CRYPTO_hash_context_read (hc, - iban, - strlen (iban) + 1); - GNUNET_CRYPTO_hash_context_read (hc, - bic, - strlen (bic) + 1); - GNUNET_CRYPTO_hash_context_finish (hc, - &mp.h_sepa_details); - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS, - &mp.purpose, - &mint_sig.eddsa_signature, - &key_state->master_pub.eddsa_pub)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return GNUNET_SYSERR; - } - MAJ_parse_free (spec); - return GNUNET_OK; -} - - -/** - * Verify that the signature on the "200 OK" response - * for /wire/METHOD from the mint is valid. - * - * @param wh wire handle with key material - * @param method method to verify the reply for - * @param json json reply with the signature - * @return #GNUNET_SYSERR if @a json is invalid, - * #GNUNET_NO if the method is unknown, - * #GNUNET_OK if the json is valid - */ -static int -verify_wire_method_signature_ok (const struct TALER_MINT_WireHandle *wh, - const char *method, - json_t *json) -{ - struct - { - /** - * Name fo the method. - */ - const char *method; - - /** - * Handler to invoke to verify signature. - * - * @param wh wire handle with key material - * @param json json reply with signature to verify - */ - int (*handler)(const struct TALER_MINT_WireHandle *wh, - json_t *json); - } handlers[] = { - { "sepa", &verify_wire_sepa_signature_ok }, - { NULL, NULL } - }; - unsigned int i; - - for (i=0;NULL != handlers[i].method; i++) - if (0 == strcasecmp (handlers[i].method, - method)) - return handlers[i].handler (wh, - json); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Wire transfer method `%s' not supported\n", - method); - return GNUNET_NO; -} - - -/** - * Perform the next /wire/method request or signal - * the end of the iteration. - * - * @param wh the wire handle - * @return a handle for this request - */ -static void -request_wire_method (struct TALER_MINT_WireHandle *wh); - - -/** - * Function called when we're done processing the - * HTTP /wire/METHOD request. - * - * @param cls the `struct TALER_MINT_WireHandle` - * @param eh the curl request handle - */ -static void -handle_wire_method_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_WireHandle *wh = cls; - long response_code; - json_t *json; - - wh->job = NULL; - json = MAC_download_get_result (&wh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - const char *method; - - method = json_string_value (json_array_get (wh->methods, - wh->methods_off - 1)); - if (GNUNET_OK != - verify_wire_method_signature_ok (wh, - method, - json)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - break; - } - case MHD_HTTP_FOUND: - /* /wire/test returns a 302 redirect, we should just give - this information back to the callback below */ - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (0 == response_code) - { - /* signal end of iteration */ - wh->cb (wh->cb_cls, - 0, - NULL, - NULL); - json_decref (json); - TALER_MINT_wire_cancel (wh); - return; - } - /* pass on successful reply */ - wh->cb (wh->cb_cls, - response_code, - json_string_value (json_array_get (wh->methods, - wh->methods_off-1)), - json); - /* trigger request for the next /wire/method */ - request_wire_method (wh); -} - - -/** - * Perform the next /wire/method request or signal - * the end of the iteration. - * - * @param wh the wire handle - * @return a handle for this request - */ -static void -request_wire_method (struct TALER_MINT_WireHandle *wh) -{ - struct TALER_MINT_Context *ctx; - CURL *eh; - char *path; - - if (json_array_size (wh->methods) <= wh->methods_off) - { - /* we are done, signal end of iteration */ - wh->cb (wh->cb_cls, - 0, - NULL, - NULL); - TALER_MINT_wire_cancel (wh); - return; - } - GNUNET_free_non_null (wh->db.buf); - wh->db.buf = NULL; - wh->db.buf_size = 0; - wh->db.eno = 0; - GNUNET_free_non_null (wh->url); - GNUNET_asprintf (&path, - "/wire/%s", - json_string_value (json_array_get (wh->methods, - wh->methods_off++))); - wh->url = MAH_path_to_url (wh->mint, - path); - GNUNET_free (path); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wh->db)); - /* The default is 'disabled', but let's be sure */ - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_FOLLOWLOCATION, - (long) 0)); - ctx = MAH_handle_to_context (wh->mint); - wh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_wire_method_finished, - wh); - TALER_MINT_perform (ctx); -} - - -/** - * Verify that the signature on the "200 OK" response - * for /wire from the mint is valid. - * - * @param wh wire handle - * @param json json reply with the signature - * @return NULL if @a json is invalid, otherwise the - * "methods" array (with an RC of 1) - */ -static json_t * -verify_wire_signature_ok (const struct TALER_MINT_WireHandle *wh, - json_t *json) -{ - struct TALER_MintSignatureP mint_sig; - struct TALER_MintPublicKeyP mint_pub; - struct TALER_MintWireSupportMethodsPS mp; - json_t *methods; - const struct TALER_MINT_Keys *key_state; - struct GNUNET_HashContext *hc; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("sig", &mint_sig), - MAJ_spec_fixed_auto ("pub", &mint_pub), - MAJ_spec_json ("methods", &methods), - MAJ_spec_end - }; - unsigned int i; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return NULL; - } - if (! json_is_array (methods)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return NULL; - } - - key_state = TALER_MINT_get_keys (wh->mint); - if (GNUNET_OK != - TALER_MINT_test_signing_key (key_state, - &mint_pub)) - { - GNUNET_break_op (0); - return NULL; - } - hc = GNUNET_CRYPTO_hash_context_start (); - for (i=0;i<json_array_size (methods);i++) - { - const json_t *element = json_array_get (methods, i); - const char *method; - - if (! json_is_string (element)) - { - GNUNET_CRYPTO_hash_context_abort (hc); - GNUNET_break_op (0); - MAJ_parse_free (spec); - return NULL; - } - method = json_string_value (element); - GNUNET_CRYPTO_hash_context_read (hc, - method, - strlen (method) + 1); - } - mp.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES); - mp.purpose.size = htonl (sizeof (struct TALER_MintWireSupportMethodsPS)); - GNUNET_CRYPTO_hash_context_finish (hc, - &mp.h_wire_types); - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_WIRE_TYPES, - &mp.purpose, - &mint_sig.eddsa_signature, - &mint_pub.eddsa_pub)) - { - GNUNET_break_op (0); - MAJ_parse_free (spec); - return NULL; - } - return methods; -} - - -/** - * Function called when we're done processing the - * HTTP /wire request. - * - * @param cls the `struct TALER_MINT_WireHandle` - * @param eh the curl request handle - */ -static void -handle_wire_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_WireHandle *wh = cls; - long response_code; - json_t *json; - - wh->job = NULL; - json = MAC_download_get_result (&wh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - json_t *methods; - - if (NULL == - (methods = verify_wire_signature_ok (wh, - json))) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - wh->methods = methods; - request_wire_method (wh); - return; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (0 != response_code) - { - /* pass on successful reply */ - wh->cb (wh->cb_cls, - response_code, - NULL, - json); - } - /* signal end of iteration */ - wh->cb (wh->cb_cls, - 0, - NULL, - NULL); - if (NULL != json) - json_decref (json); - TALER_MINT_wire_cancel (wh); -} - - -/** - * Obtain information about a mint's wire instructions. - * A mint may provide wire instructions for creating - * a reserve. The wire instructions also indicate - * which wire formats merchants may use with the mint. - * This API is typically used by a wallet for wiring - * funds, and possibly by a merchant to determine - * supported wire formats. - * - * Note that while we return the (main) response verbatim to the - * caller for further processing, we do already verify that the - * response is well-formed (i.e. that signatures included in the - * response are all valid). If the mint's reply is not well-formed, - * we return an HTTP status code of zero to @a cb. - * - * @param mint the mint handle; the mint must be ready to operate - * @param wire_cb the callback to call when a reply for this request is available - * @param wire_cb_cls closure for the above callback - * @return a handle for this request - */ -struct TALER_MINT_WireHandle * -TALER_MINT_wire (struct TALER_MINT_Handle *mint, - TALER_MINT_WireResultCallback wire_cb, - void *wire_cb_cls) -{ - struct TALER_MINT_WireHandle *wh; - struct TALER_MINT_Context *ctx; - CURL *eh; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - wh = GNUNET_new (struct TALER_MINT_WireHandle); - wh->mint = mint; - wh->cb = wire_cb; - wh->cb_cls = wire_cb_cls; - wh->url = MAH_path_to_url (mint, "/wire"); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wh->db)); - ctx = MAH_handle_to_context (mint); - wh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_wire_finished, - wh); - return wh; -} - - -/** - * Cancel a wire information request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param wh the wire information request handle - */ -void -TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wh) -{ - if (NULL != wh->job) - { - MAC_job_cancel (wh->job); - wh->job = NULL; - } - if (NULL != wh->methods) - { - json_decref (wh->methods); - wh->methods = NULL; - } - GNUNET_free_non_null (wh->db.buf); - GNUNET_free (wh->url); - GNUNET_free (wh); -} - - -/* end of mint_api_wire.c */ diff --git a/src/mint-lib/mint_api_wire_deposits.c b/src/mint-lib/mint_api_wire_deposits.c deleted file mode 100644 index f71c5b696..000000000 --- a/src/mint-lib/mint_api_wire_deposits.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_wire_deposits.c - * @brief Implementation of the /wire/deposits request of the mint's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A /wire/deposits Handle - */ -struct TALER_MINT_WireDepositsHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_WireDepositsCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - -}; - - -/** - * Function called when we're done processing the - * HTTP /wire/deposits request. - * - * @param cls the `struct TALER_MINT_WireDepositsHandle` - * @param eh the curl request handle - */ -static void -handle_wire_deposits_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_WireDepositsHandle *wdh = cls; - long response_code; - json_t *json; - - wdh->job = NULL; - json = MAC_download_get_result (&wdh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - json_t *details_j; - struct GNUNET_HashCode h_wire; - struct TALER_Amount total_amount; - struct TALER_MerchantPublicKeyP merchant_pub; - unsigned int num_details; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("H_wire", &h_wire), - MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub), - MAJ_spec_amount ("total_amount", &total_amount), - MAJ_spec_json ("details", &details_j), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - num_details = json_array_size (details_j); - { - struct TALER_WireDepositDetails details[num_details]; - unsigned int i; - - for (i=0;i<num_details;i++) - { - struct TALER_WireDepositDetails *detail = &details[i]; - struct json_t *detail_j = json_array_get (details_j, i); - struct MAJ_Specification spec_detail[] = { - MAJ_spec_fixed_auto ("H_contract", &detail->h_contract), - MAJ_spec_amount ("deposit_value", &detail->coin_value), - MAJ_spec_amount ("deposit_fee", &detail->coin_fee), - MAJ_spec_uint64 ("transaction_id", &detail->transaction_id), - MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (detail_j, - spec_detail)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - } - if (0 == response_code) - break; - wdh->cb (wdh->cb_cls, - response_code, - json, - &h_wire, - &total_amount, - num_details, - details); - json_decref (json); - TALER_MINT_wire_deposits_cancel (wdh); - return; - } - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Mint does not know about transaction; - we should pass the reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - wdh->cb (wdh->cb_cls, - response_code, - json, - NULL, NULL, 0, NULL); - json_decref (json); - TALER_MINT_wire_deposits_cancel (wdh); -} - - -/** - * Query the mint about which transactions were combined - * to create a wire transfer. - * - * @param mint mint to query - * @param wtid raw wire transfer identifier to get information about - * @param cb callback to call - * @param cb_cls closure for @a cb - * @return handle to cancel operation - */ -struct TALER_MINT_WireDepositsHandle * -TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint, - const struct TALER_WireTransferIdentifierRawP *wtid, - TALER_MINT_WireDepositsCallback cb, - void *cb_cls) -{ - struct TALER_MINT_WireDepositsHandle *wdh; - struct TALER_MINT_Context *ctx; - char *buf; - char *path; - CURL *eh; - - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - - wdh = GNUNET_new (struct TALER_MINT_WireDepositsHandle); - wdh->mint = mint; - wdh->cb = cb; - wdh->cb_cls = cb_cls; - - buf = GNUNET_STRINGS_data_to_string_alloc (wtid, - sizeof (struct TALER_WireTransferIdentifierRawP)); - GNUNET_asprintf (&path, - "/wire/deposits?wtid=%s", - buf); - wdh->url = MAH_path_to_url (wdh->mint, - path); - GNUNET_free (buf); - GNUNET_free (path); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wdh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wdh->db)); - ctx = MAH_handle_to_context (mint); - wdh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_wire_deposits_finished, - wdh); - return wdh; -} - - -/** - * Cancel wire deposits request. This function cannot be used on a request - * handle if a response is already served for it. - * - * @param wdh the wire deposits request handle - */ -void -TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh) -{ - if (NULL != wdh->job) - { - MAC_job_cancel (wdh->job); - wdh->job = NULL; - } - GNUNET_free_non_null (wdh->db.buf); - GNUNET_free (wdh->url); - GNUNET_free (wdh); -} - - -/* end of mint_api_wire_deposits.c */ diff --git a/src/mint-lib/test-mint-home/config/mint-common.conf b/src/mint-lib/test-mint-home/config/mint-common.conf deleted file mode 100644 index b2b948268..000000000 --- a/src/mint-lib/test-mint-home/config/mint-common.conf +++ /dev/null @@ -1,30 +0,0 @@ -[mint] -# Currency supported by the mint (can only be one) -CURRENCY = EUR - -# Wire format supported by the mint -# We use 'test' for testing of the actual -# coin operations, and 'sepa' to test SEPA-specific routines. -WIREFORMAT = test sepa - -# HTTP port the mint listens to -PORT = 8081 - -# Master public key used to sign the mint's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Is this is a testcase, use transient DB actions? -TESTRUN = YES - -[mintdb-postgres] - -DB_CONN_STR = "postgres:///talercheck" - -[mint-wire-sepa] -SEPA_RESPONSE_FILE = "test-mint-home/sepa.json" - -[mint-wire-test] -REDIRECT_URL = "http://www.taler.net/" diff --git a/src/mint-lib/test-mint-home/config/mint-keyup.conf b/src/mint-lib/test-mint-home/config/mint-keyup.conf deleted file mode 100644 index 8ad1f3bb2..000000000 --- a/src/mint-lib/test-mint-home/config/mint-keyup.conf +++ /dev/null @@ -1,86 +0,0 @@ -[mint_keys] - -# how long is one signkey valid? -signkey_duration = 4 weeks - -# how long are the signatures with the signkey valid? -legal_duration = 2 years - -# how long do we generate denomination and signing keys -# ahead of time? -lookahead_sign = 32 weeks 1 day - -# how long do we provide to clients denomination and signing keys -# ahead of time? -lookahead_provide = 4 weeks 1 day - - -# Coin definitions are detected because the section -# name begins with "coin_". The rest of the -# name is free, but of course following the convention -# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense. -[coin_eur_ct_1] -value = EUR:0.01 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -rsa_keysize = 1024 - -[coin_eur_ct_10] -value = EUR:0.10 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -rsa_keysize = 1024 - -[coin_eur_1] -value = EUR:1 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -rsa_keysize = 1024 - -[coin_eur_5] -value = EUR:5 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -rsa_keysize = 1024 - -[coin_eur_10] -value = EUR:10 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -rsa_keysize = 1024 - -[coin_eur_1000] -value = EUR:1000 -duration_overlap = 5 minutes -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -rsa_keysize = 2048 diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c deleted file mode 100644 index b243cc2cf..000000000 --- a/src/mint-lib/test_mint_api.c +++ /dev/null @@ -1,2599 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/test_mint_api.c - * @brief testcase to test mint's HTTP API interface - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_mint_service.h" -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> - -/** - * Is the configuration file is set to include wire format 'test'? - */ -#define WIRE_TEST 1 - -/** - * Is the configuration file is set to include wire format 'sepa'? - */ -#define WIRE_SEPA 1 - -/** - * Main execution context for the main loop. - */ -static struct TALER_MINT_Context *ctx; - -/** - * Handle to access the mint. - */ -static struct TALER_MINT_Handle *mint; - -/** - * Task run on shutdown. - */ -static struct GNUNET_SCHEDULER_Task *shutdown_task; - -/** - * Task that runs the main event loop. - */ -static struct GNUNET_SCHEDULER_Task *ctx_task; - -/** - * Result of the testcases, #GNUNET_OK on success - */ -static int result; - - -/** - * Opcodes for the interpreter. - */ -enum OpCode -{ - /** - * Termination code, stops the interpreter loop (with success). - */ - OC_END = 0, - - /** - * Add funds to a reserve by (faking) incoming wire transfer. - */ - OC_ADMIN_ADD_INCOMING, - - /** - * Check status of a reserve. - */ - OC_WITHDRAW_STATUS, - - /** - * Withdraw a coin from a reserve. - */ - OC_WITHDRAW_SIGN, - - /** - * Deposit a coin (pay with it). - */ - OC_DEPOSIT, - - /** - * Melt a (set of) coins. - */ - OC_REFRESH_MELT, - - /** - * Complete melting session by withdrawing melted coins. - */ - OC_REFRESH_REVEAL, - - /** - * Verify mint's /refresh/link by linking original private key to - * results from #OC_REFRESH_REVEAL step. - */ - OC_REFRESH_LINK, - - /** - * Verify the mint's /wire-method. - */ - OC_WIRE, - - /** - * Verify mint's /wire/deposits method. - */ - OC_WIRE_DEPOSITS, - - /** - * Verify mint's /deposit/wtid method. - */ - OC_DEPOSIT_WTID - -}; - - -/** - * Structure specifying details about a coin to be melted. - * Used in a NULL-terminated array as part of command - * specification. - */ -struct MeltDetails -{ - - /** - * Amount to melt (including fee). - */ - const char *amount; - - /** - * Reference to reserve_withdraw operations for coin to - * be used for the /refresh/melt operation. - */ - const char *coin_ref; - -}; - - -/** - * Information about a fresh coin generated by the refresh operation. - */ -struct FreshCoin -{ - - /** - * If @e amount is NULL, this specifies the denomination key to - * use. Otherwise, this will be set (by the interpreter) to the - * denomination PK matching @e amount. - */ - const struct TALER_MINT_DenomPublicKey *pk; - - /** - * Set (by the interpreter) to the mint's signature over the - * coin's public key. - */ - struct TALER_DenominationSignature sig; - - /** - * Set (by the interpreter) to the coin's private key. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - -}; - - -/** - * Details for a mint operation to execute. - */ -struct Command -{ - /** - * Opcode of the command. - */ - enum OpCode oc; - - /** - * Label for the command, can be NULL. - */ - const char *label; - - /** - * Which response code do we expect for this command? - */ - unsigned int expected_response_code; - - /** - * Details about the command. - */ - union - { - - /** - * Information for a #OC_ADMIN_ADD_INCOMING command. - */ - struct - { - - /** - * Label to another admin_add_incoming command if we - * should deposit into an existing reserve, NULL if - * a fresh reserve should be created. - */ - const char *reserve_reference; - - /** - * String describing the amount to add to the reserve. - */ - const char *amount; - - /** - * Wire details (JSON). - */ - const char *wire; - - /** - * Set (by the interpreter) to the reserve's private key - * we used to fill the reserve. - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Set to the API's handle during the operation. - */ - struct TALER_MINT_AdminAddIncomingHandle *aih; - - } admin_add_incoming; - - /** - * Information for a #OC_WITHDRAW_STATUS command. - */ - struct - { - - /** - * Label to the #OC_ADMIN_ADD_INCOMING command which - * created the reserve. - */ - const char *reserve_reference; - - /** - * Set to the API's handle during the operation. - */ - struct TALER_MINT_ReserveStatusHandle *wsh; - - /** - * Expected reserve balance. - */ - const char *expected_balance; - - } reserve_status; - - /** - * Information for a #OC_WITHDRAW_SIGN command. - */ - struct - { - - /** - * Which reserve should we withdraw from? - */ - const char *reserve_reference; - - /** - * String describing the denomination value we should withdraw. - * A corresponding denomination key must exist in the mint's - * offerings. Can be NULL if @e pk is set instead. - */ - const char *amount; - - /** - * If @e amount is NULL, this specifies the denomination key to - * use. Otherwise, this will be set (by the interpreter) to the - * denomination PK matching @e amount. - */ - const struct TALER_MINT_DenomPublicKey *pk; - - /** - * Set (by the interpreter) to the mint's signature over the - * coin's public key. - */ - struct TALER_DenominationSignature sig; - - /** - * Set (by the interpreter) to the coin's private key. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * Blinding key used for the operation. - */ - struct TALER_DenominationBlindingKey blinding_key; - - /** - * Withdraw handle (while operation is running). - */ - struct TALER_MINT_ReserveWithdrawHandle *wsh; - - } reserve_withdraw; - - /** - * Information for a #OC_DEPOSIT command. - */ - struct - { - - /** - * Amount to deposit. - */ - const char *amount; - - /** - * Reference to a reserve_withdraw operation for a coin to - * be used for the /deposit operation. - */ - const char *coin_ref; - - /** - * If this @e coin_ref refers to an operation that generated - * an array of coins, this value determines which coin to use. - */ - unsigned int coin_idx; - - /** - * JSON string describing the merchant's "wire details". - */ - const char *wire_details; - - /** - * JSON string describing the contract between the two parties. - */ - const char *contract; - - /** - * Transaction ID to use. - */ - uint64_t transaction_id; - - /** - * Relative time (to add to 'now') to compute the refund deadline. - * Zero for no refunds. - */ - struct GNUNET_TIME_Relative refund_deadline; - - /** - * Set (by the interpreter) to a fresh private key of the merchant, - * if @e refund_deadline is non-zero. - */ - struct TALER_MerchantPrivateKeyP merchant_priv; - - /** - * Deposit handle while operation is running. - */ - struct TALER_MINT_DepositHandle *dh; - - } deposit; - - /** - * Information for a #OC_REFRESH_MELT command. - */ - struct - { - - /** - * Information about coins to be melted. - */ - struct MeltDetails *melted_coins; - - /** - * Denominations of the fresh coins to withdraw. - */ - const char **fresh_amounts; - - /** - * Array of the public keys corresponding to - * the @e fresh_amounts, set by the interpreter. - */ - const struct TALER_MINT_DenomPublicKey **fresh_pks; - - /** - * Melt handle while operation is running. - */ - struct TALER_MINT_RefreshMeltHandle *rmh; - - /** - * Data used in the refresh operation, set by the interpreter. - */ - char *refresh_data; - - /** - * Number of bytes in @e refresh_data, set by the interpreter. - */ - size_t refresh_data_length; - - /** - * Set by the interpreter (upon completion) to the noreveal - * index selected by the mint. - */ - uint16_t noreveal_index; - - } refresh_melt; - - /** - * Information for a #OC_REFRESH_REVEAL command. - */ - struct - { - - /** - * Melt operation this is the matching reveal for. - */ - const char *melt_ref; - - /** - * Reveal handle while operation is running. - */ - struct TALER_MINT_RefreshRevealHandle *rrh; - - /** - * Number of fresh coins withdrawn, set by the interpreter. - * Length of the @e fresh_coins array. - */ - unsigned int num_fresh_coins; - - /** - * Information about coins withdrawn, set by the interpreter. - */ - struct FreshCoin *fresh_coins; - - } refresh_reveal; - - /** - * Information for a #OC_REFRESH_LINK command. - */ - struct - { - - /** - * Reveal operation this is the matching link for. - */ - const char *reveal_ref; - - /** - * Link handle while operation is running. - */ - struct TALER_MINT_RefreshLinkHandle *rlh; - - /** - * Which of the melted coins should be used for the linkage? - */ - unsigned int coin_idx; - - } refresh_link; - - /** - * Information for the /wire command. - */ - struct { - - /** - * Handle to the wire request. - */ - struct TALER_MINT_WireHandle *wh; - - /** - * Format we expect to see, others will be *ignored*. - */ - const char *format; - - } wire; - - /** - * Information for the /wire/deposits's command. - */ - struct { - - /** - * Handle to the wire deposits request. - */ - struct TALER_MINT_WireDepositsHandle *wdh; - - /** - * Reference to a /deposit/wtid command. If set, we use the - * WTID from that command. - */ - const char *wtid_ref; - - /** - * WTID to use (used if @e wtid_ref is NULL). - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /* TODO: may want to add list of deposits we expected - to see aggregated here in the future. */ - - } wire_deposits; - - /** - * Information for the /deposit/wtid command. - */ - struct { - - /** - * Handle to the deposit wtid request. - */ - struct TALER_MINT_DepositWtidHandle *dwh; - - /** - * Which /deposit operation should we obtain WTID data for? - */ - const char *deposit_ref; - - /** - * What is the expected total amount? Only used if - * @e expected_response_code was #MHD_HTTP_OK. - */ - struct TALER_Amount total_amount_expected; - - /** - * Wire transfer identifier, set if #MHD_HTTP_OK was the response code. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - } deposit_wtid; - - } details; - -}; - - -/** - * State of the interpreter loop. - */ -struct InterpreterState -{ - /** - * Keys from the mint. - */ - const struct TALER_MINT_Keys *keys; - - /** - * Commands the interpreter will run. - */ - struct Command *commands; - - /** - * Interpreter task (if one is scheduled). - */ - struct GNUNET_SCHEDULER_Task *task; - - /** - * Instruction pointer. Tells #interpreter_run() which - * instruction to run next. - */ - unsigned int ip; - -}; - - -/** - * Task that runs the context's event loop with the GNUnet scheduler. - * - * @param cls unused - * @param tc scheduler context (unused) - */ -static void -context_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Run the context task, the working set has changed. - */ -static void -trigger_context_task () -{ - GNUNET_SCHEDULER_cancel (ctx_task); - ctx_task = GNUNET_SCHEDULER_add_now (&context_task, - NULL); -} - - -/** - * The testcase failed, return with an error code. - * - * @param is interpreter state to clean up - */ -static void -fail (struct InterpreterState *is) -{ - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Find a command by label. - * - * @param is interpreter state to search - * @param label label to look for - * @return NULL if command was not found - */ -static const struct Command * -find_command (const struct InterpreterState *is, - const char *label) -{ - unsigned int i; - const struct Command *cmd; - - if (NULL == label) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Attempt to lookup command for empty label\n"); - return NULL; - } - for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++) - if ( (NULL != cmd->label) && - (0 == strcmp (cmd->label, - label)) ) - return cmd; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command not found: %s\n", - label); - return NULL; -} - - -/** - * Run the main interpreter loop that performs mint operations. - * - * @param cls contains the `struct InterpreterState` - * @param tc scheduler context - */ -static void -interpreter_run (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Function called upon completion of our /admin/add/incoming request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -add_incoming_cb (void *cls, - unsigned int http_status, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.admin_add_incoming.aih = NULL; - if (MHD_HTTP_OK != http_status) - { - GNUNET_break (0); - fail (is); - return; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Check if the given historic event @a h corresponds to the given - * command @a cmd. - * - * @param h event in history - * @param cmd an #OC_ADMIN_ADD_INCOMING command - * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not - */ -static int -compare_admin_add_incoming_history (const struct TALER_MINT_ReserveHistory *h, - const struct Command *cmd) -{ - struct TALER_Amount amount; - - if (TALER_MINT_RTT_DEPOSIT != h->type) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.admin_add_incoming.amount, - &amount)); - if (0 != TALER_amount_cmp (&amount, - &h->amount)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Check if the given historic event @a h corresponds to the given - * command @a cmd. - * - * @param h event in history - * @param cmd an #OC_WITHDRAW_SIGN command - * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not - */ -static int -compare_reserve_withdraw_history (const struct TALER_MINT_ReserveHistory *h, - const struct Command *cmd) -{ - struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; - - if (TALER_MINT_RTT_WITHDRAWAL != h->type) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.reserve_withdraw.amount, - &amount)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&amount_with_fee, - &amount, - &cmd->details.reserve_withdraw.pk->fee_withdraw)); - if (0 != TALER_amount_cmp (&amount_with_fee, - &h->amount)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function called with the result of a /reserve/status request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param[in] json original response in JSON format (useful only for diagnostics) - * @param balance current balance in the reserve, NULL on error - * @param history_length number of entries in the transaction history, 0 on error - * @param history detailed transaction history, NULL on error - */ -static void -reserve_status_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_Amount *balance, - unsigned int history_length, - const struct TALER_MINT_ReserveHistory *history) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - struct Command *rel; - unsigned int i; - unsigned int j; - struct TALER_Amount amount; - - cmd->details.reserve_status.wsh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - GNUNET_break (0); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - /* FIXME: note that history events may come in a different - order than the commands. However, for now this works... */ - j = 0; - for (i=0;i<is->ip;i++) - { - switch ((rel = &is->commands[i])->oc) - { - case OC_ADMIN_ADD_INCOMING: - if ( ( (NULL != rel->label) && - (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->label) ) ) || - ( (NULL != rel->details.admin_add_incoming.reserve_reference) && - (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->details.admin_add_incoming.reserve_reference) ) ) ) - { - if (GNUNET_OK != - compare_admin_add_incoming_history (&history[j], - rel)) - { - GNUNET_break (0); - fail (is); - return; - } - j++; - } - break; - case OC_WITHDRAW_SIGN: - if (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->details.reserve_withdraw.reserve_reference)) - { - if (GNUNET_OK != - compare_reserve_withdraw_history (&history[j], - rel)) - { - GNUNET_break (0); - fail (is); - return; - } - j++; - } - break; - default: - /* unreleated, just skip */ - break; - } - } - if (j != history_length) - { - GNUNET_break (0); - fail (is); - return; - } - if (NULL != cmd->details.reserve_status.expected_balance) - { - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.reserve_status.expected_balance, - &amount)); - if (0 != TALER_amount_cmp (&amount, - balance)) - { - GNUNET_break (0); - fail (is); - return; - } - } - break; - default: - /* Unsupported status code (by test harness) */ - GNUNET_break (0); - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called upon completion of our /reserve/withdraw request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param sig signature over the coin, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -reserve_withdraw_cb (void *cls, - unsigned int http_status, - const struct TALER_DenominationSignature *sig, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.reserve_withdraw.wsh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - GNUNET_break (0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - if (NULL == sig) - { - GNUNET_break (0); - fail (is); - return; - } - cmd->details.reserve_withdraw.sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); - break; - case MHD_HTTP_PAYMENT_REQUIRED: - /* nothing to check */ - break; - default: - /* Unsupported status code (by test harness) */ - GNUNET_break (0); - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of a /deposit operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param obj the received JSON reply, should be kept as proof (and, in case of errors, - * be forwarded to the customer) - */ -static void -deposit_cb (void *cls, - unsigned int http_status, - json_t *obj) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.deposit.dh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (obj, stderr, 0); - fail (is); - return; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of the /refresh/melt operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param noreveal_index choice by the mint in the cut-and-choose protocol, - * UINT16_MAX on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -melt_cb (void *cls, - unsigned int http_status, - uint16_t noreveal_index, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.refresh_melt.rmh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - cmd->details.refresh_melt.noreveal_index = noreveal_index; - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of the /refresh/reveal operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param sigs array of signature over @a num_coins coins, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -reveal_cb (void *cls, - unsigned int http_status, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - unsigned int i; - - cmd->details.refresh_reveal.rrh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - ref = find_command (is, - cmd->details.refresh_reveal.melt_ref); - cmd->details.refresh_reveal.num_fresh_coins = num_coins; - switch (http_status) - { - case MHD_HTTP_OK: - cmd->details.refresh_reveal.fresh_coins - = GNUNET_new_array (num_coins, - struct FreshCoin); - for (i=0;i<num_coins;i++) - { - struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i]; - - fc->pk = ref->details.refresh_melt.fresh_pks[i]; - fc->coin_priv = coin_privs[i]; - fc->sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature); - } - break; - default: - break; - } - - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of a /refresh/link operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param sigs array of signature over @a num_coins coins, NULL on error - * @param pubs array of public keys for the @a sigs, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -link_cb (void *cls, - unsigned int http_status, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const struct TALER_DenominationPublicKey *pubs, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - unsigned int i; - unsigned int j; - unsigned int found; - - cmd->details.refresh_link.rlh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - ref = find_command (is, - cmd->details.refresh_link.reveal_ref); - switch (http_status) - { - case MHD_HTTP_OK: - /* check that number of coins returned matches */ - if (num_coins != ref->details.refresh_reveal.num_fresh_coins) - { - GNUNET_break (0); - fail (is); - return; - } - /* check that the coins match */ - for (i=0;i<num_coins;i++) - for (j=i+1;j<num_coins;j++) - if (0 == memcmp (&coin_privs[i], - &coin_privs[j], - sizeof (struct TALER_CoinSpendPrivateKeyP))) - GNUNET_break (0); - /* Note: coins might be legitimately permutated in here... */ - found = 0; - for (i=0;i<num_coins;i++) - for (j=0;j<num_coins;j++) - { - const struct FreshCoin *fc; - - fc = &ref->details.refresh_reveal.fresh_coins[j]; - if ( (0 == memcmp (&coin_privs[i], - &fc->coin_priv, - sizeof (struct TALER_CoinSpendPrivateKeyP))) && - (0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature, - sigs[i].rsa_signature)) && - (0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key, - pubs[i].rsa_public_key)) ) - { - found++; - break; - } - } - if (found != num_coins) - { - fprintf (stderr, - "Only %u/%u coins match expectations\n", - found, - num_coins); - GNUNET_break (0); - fail (is); - return; - } - break; - default: - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Find denomination key matching the given amount. - * - * @param keys array of keys to search - * @param amount coin value to look for - * @return NULL if no matching key was found - */ -static const struct TALER_MINT_DenomPublicKey * -find_pk (const struct TALER_MINT_Keys *keys, - const struct TALER_Amount *amount) -{ - unsigned int i; - struct GNUNET_TIME_Absolute now; - struct TALER_MINT_DenomPublicKey *pk; - char *str; - - now = GNUNET_TIME_absolute_get (); - for (i=0;i<keys->num_denom_keys;i++) - { - pk = &keys->denom_keys[i]; - if ( (0 == TALER_amount_cmp (amount, - &pk->value)) && - (now.abs_value_us >= pk->valid_from.abs_value_us) && - (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) ) - return pk; - } - /* do 2nd pass to check if expiration times are to blame for failure */ - str = TALER_amount_to_string (amount); - for (i=0;i<keys->num_denom_keys;i++) - { - pk = &keys->denom_keys[i]; - if ( (0 == TALER_amount_cmp (amount, - &pk->value)) && - ( (now.abs_value_us < pk->valid_from.abs_value_us) || - (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n", - str, - now.abs_value_us, - pk->valid_from.abs_value_us, - pk->withdraw_valid_until.abs_value_us); - GNUNET_free (str); - return NULL; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No denomination key for amount %s found\n", - str); - GNUNET_free (str); - return NULL; -} - - -/** - * Callbacks called with the result(s) of a - * wire format inquiry request to the mint. - * - * The callback is invoked multiple times, once for each supported @a - * method. Finally, it is invoked one more time with cls/0/NULL/NULL - * to indicate the end of the iteration. If any request fails to - * generate a valid response from the mint, @a http_status will also - * be zero and the iteration will also end. Thus, the iteration - * always ends with a final call with an @a http_status of 0. If the - * @a http_status is already 0 on the first call, then the response to - * the /wire request was invalid. Later, clients can tell the - * difference between @a http_status of 0 indicating a failed - * /wire/method request and a regular end of the iteration by @a - * method being non-NULL. If the mint simply correctly asserts that - * it does not support any methods, @a method will be NULL but the @a - * http_status will be #MHD_HTTP_OK for the first call (followed by a - * cls/0/NULL/NULL call to signal the end of the iteration). - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param method wire format method supported, i.e. "test" or "sepa", or NULL - * if already the /wire request failed. - * @param obj the received JSON reply, if successful this should be the wire - * format details as provided by /wire/METHOD/, or NULL if the - * reply was not in JSON format (in this case, the client might - * want to do an HTTP request to /wire/METHOD/ with a browser to - * provide more information to the user about the @a method). - */ -static void -wire_cb (void *cls, - unsigned int http_status, - const char *method, - json_t *obj) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - if (0 == http_status) - { - /* 0 always signals the end of the iteration */ - cmd->details.wire.wh = NULL; - } - else if ( (NULL != method) && - (0 != strcasecmp (method, - cmd->details.wire.format)) ) - { - /* not the method we care about, skip */ - return; - } - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s/%s\n", - http_status, - cmd->label, - method); - json_dumpf (obj, stderr, 0); - fail (is); - return; - } - if (0 == http_status) - { - /* end of iteration, move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); - return; - } - /* For now, we only support to be called only once - with a "positive" result; so we switch to an - expected value of 0 for the 2nd iteration */ - cmd->expected_response_code = 0; -} - - -/** - * Function called with detailed wire transfer data, including all - * of the coin transactions that were combined into the wire transfer. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid extracted wire transfer identifier, or NULL if the mint could - * not provide any (set only if @a http_status is #MHD_HTTP_OK) - * @param total_amount total amount of the wire transfer, or NULL if the mint could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - * @param details_length length of the @a details array - * @param details array with details about the combined transactions - */ -static void -wire_deposits_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct GNUNET_HashCode *h_wire, - const struct TALER_Amount *total_amount, - unsigned int details_length, - const struct TALER_WireDepositDetails *details) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - - cmd->details.wire_deposits.wdh = NULL; - ref = find_command (is, - cmd->details.wire_deposits.wtid_ref); - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - if (0 != TALER_amount_cmp (total_amount, - &ref->details.deposit_wtid.total_amount_expected)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount missmatch to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - if (NULL != ref->details.deposit_wtid.deposit_ref) - { - const struct Command *dep; - struct GNUNET_HashCode hw; - - dep = find_command (is, - ref->details.deposit_wtid.deposit_ref); - GNUNET_CRYPTO_hash (dep->details.deposit.wire_details, - strlen (dep->details.deposit.wire_details), - &hw); - if (0 != memcmp (&hw, - h_wire, - sizeof (struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire hash missmatch to command %s\n", - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - } - break; - default: - break; - } - - /* move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with detailed wire transfer data. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid wire transfer identifier used by the mint, NULL if mint did not - * yet execute the transaction - * @param execution_time actual or planned execution time for the wire transfer - * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL) - * @param total_amount total amount of the wire transfer, or NULL if the mint could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - */ -static void -deposit_wtid_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_Amount *coin_contribution) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.deposit_wtid.dwh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - cmd->details.deposit_wtid.wtid = *wtid; - break; - default: - break; - } - - /* move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Run the main interpreter loop that performs mint operations. - * - * @param cls contains the `struct InterpreterState` - * @param tc scheduler context - */ -static void -interpreter_run (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount amount; - struct GNUNET_TIME_Absolute execution_date; - json_t *wire; - - is->task = NULL; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - fprintf (stderr, - "Test aborted by shutdown request\n"); - fail (is); - return; - } - switch (cmd->oc) - { - case OC_END: - result = GNUNET_OK; - GNUNET_SCHEDULER_shutdown (); - return; - case OC_ADMIN_ADD_INCOMING: - if (NULL != - cmd->details.admin_add_incoming.reserve_reference) - { - ref = find_command (is, - cmd->details.admin_add_incoming.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - cmd->details.admin_add_incoming.reserve_priv - = ref->details.admin_add_incoming.reserve_priv; - } - else - { - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.admin_add_incoming.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.admin_add_incoming.amount, - is->ip); - fail (is); - return; - } - wire = json_loads (cmd->details.admin_add_incoming.wire, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == wire) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse wire details `%s' at %u\n", - cmd->details.admin_add_incoming.wire, - is->ip); - fail (is); - return; - } - execution_date = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (&execution_date); - cmd->details.admin_add_incoming.aih - = TALER_MINT_admin_add_incoming (mint, - &reserve_pub, - &amount, - execution_date, - wire, - &add_incoming_cb, - is); - if (NULL == cmd->details.admin_add_incoming.aih) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_WITHDRAW_STATUS: - GNUNET_assert (NULL != - cmd->details.reserve_status.reserve_reference); - ref = find_command (is, - cmd->details.reserve_status.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - cmd->details.reserve_status.wsh - = TALER_MINT_reserve_status (mint, - &reserve_pub, - &reserve_status_cb, - is); - trigger_context_task (); - return; - case OC_WITHDRAW_SIGN: - GNUNET_assert (NULL != - cmd->details.reserve_withdraw.reserve_reference); - ref = find_command (is, - cmd->details.reserve_withdraw.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - if (NULL != cmd->details.reserve_withdraw.amount) - { - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.reserve_withdraw.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.reserve_withdraw.amount, - is->ip); - fail (is); - return; - } - cmd->details.reserve_withdraw.pk = find_pk (is->keys, - &amount); - } - if (NULL == cmd->details.reserve_withdraw.pk) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to determine denomination key at %u\n", - is->ip); - fail (is); - return; - } - - /* create coin's private key */ - { - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key - = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key)); - cmd->details.reserve_withdraw.wsh - = TALER_MINT_reserve_withdraw (mint, - cmd->details.reserve_withdraw.pk, - &ref->details.admin_add_incoming.reserve_priv, - &cmd->details.reserve_withdraw.coin_priv, - &cmd->details.reserve_withdraw.blinding_key, - &reserve_withdraw_cb, - is); - if (NULL == cmd->details.reserve_withdraw.wsh) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_DEPOSIT: - { - struct GNUNET_HashCode h_contract; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - const struct TALER_MINT_DenomPublicKey *coin_pk; - const struct TALER_DenominationSignature *coin_pk_sig; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_CoinSpendSignatureP coin_sig; - struct GNUNET_TIME_Absolute refund_deadline; - struct GNUNET_TIME_Absolute wire_deadline; - struct GNUNET_TIME_Absolute timestamp; - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - struct TALER_MerchantPublicKeyP merchant_pub; - json_t *contract; - json_t *wire; - - GNUNET_assert (NULL != - cmd->details.deposit.coin_ref); - ref = find_command (is, - cmd->details.deposit.coin_ref); - GNUNET_assert (NULL != ref); - switch (ref->oc) - { - case OC_WITHDRAW_SIGN: - coin_priv = &ref->details.reserve_withdraw.coin_priv; - coin_pk = ref->details.reserve_withdraw.pk; - coin_pk_sig = &ref->details.reserve_withdraw.sig; - break; - case OC_REFRESH_REVEAL: - { - const struct FreshCoin *fc; - unsigned int idx; - - idx = cmd->details.deposit.coin_idx; - GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins); - fc = &ref->details.refresh_reveal.fresh_coins[idx]; - - coin_priv = &fc->coin_priv; - coin_pk = fc->pk; - coin_pk_sig = &fc->sig; - } - break; - default: - GNUNET_assert (0); - } - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.deposit.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.deposit.amount, - is->ip); - fail (is); - return; - } - contract = json_loads (cmd->details.deposit.contract, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == contract) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse contract details `%s' at %u/%s\n", - cmd->details.deposit.contract, - is->ip, - cmd->label); - fail (is); - return; - } - TALER_hash_json (contract, - &h_contract); - wire = json_loads (cmd->details.deposit.wire_details, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == wire) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse wire details `%s' at %u/%s\n", - cmd->details.deposit.wire_details, - is->ip, - cmd->label); - fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.deposit.merchant_priv.eddsa_priv = *priv; - GNUNET_free (priv); - if (0 != cmd->details.deposit.refund_deadline.rel_value_us) - { - refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline); - } - else - { - refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS; - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv, - &merchant_pub.eddsa_pub); - - wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS); - timestamp = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (×tamp); - { - 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", - ¶ms->duration_withdraw)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - ct, - "duration_withdraw"); - return GNUNET_SYSERR; - } - TALER_round_rel_time (¶ms->duration_withdraw); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - ct, - "duration_spend", - ¶ms->duration_spend)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - ct, - "duration_spend"); - return GNUNET_SYSERR; - } - TALER_round_rel_time (¶ms->duration_spend); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - ct, - "duration_legal", - ¶ms->duration_legal)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - ct, - "duration_legal"); - return GNUNET_SYSERR; - } - TALER_round_rel_time (¶ms->duration_legal); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - ct, - "duration_overlap", - ¶ms->duration_overlap)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - ct, - "mint_denom_duration_overlap"); - return GNUNET_SYSERR; - } - TALER_round_rel_time (¶ms->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", - ¶ms->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", - ¶ms->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", - ¶ms->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", - ¶ms->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, - ¶ms->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, - ¶ms->value); - TALER_amount_hton (&dki->issue.properties.fee_withdraw, - ¶ms->fee_withdraw); - TALER_amount_hton (&dki->issue.properties.fee_deposit, - ¶ms->fee_deposit); - TALER_amount_hton (&dki->issue.properties.fee_refresh, - ¶ms->fee_refresh); - dki->issue.properties.purpose.purpose - = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); - dki->issue.properties.purpose.size - = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv, - &dki->issue.properties.purpose, - &dki->issue.signature.eddsa_signature)); -} - - -/** - * Generate new coin signing keys for the coin type of the given @a - * coin_alias. - * - * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure - * @param coin_alias name of the coin's section in the configuration - */ -static void -mint_keys_update_cointype (void *cls, - const char *coin_alias) -{ - int *ret = cls; - struct CoinTypeParams p; - const char *dkf; - struct TALER_MINTDB_DenominationKeyIssueInformation denomkey_issue; - - if (0 != strncasecmp (coin_alias, - "coin_", - strlen ("coin_"))) - return; /* not a coin definition */ - if (GNUNET_OK != - get_cointype_params (coin_alias, - &p)) - { - *ret = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - GNUNET_DISK_directory_create (get_cointype_dir (&p))) - { - *ret = GNUNET_SYSERR; - return; - } - - while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) - { - dkf = get_cointype_file (&p, - p.anchor); - GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Generating denomination key for type `%s', start %s at %s\n", - coin_alias, - GNUNET_STRINGS_absolute_time_to_string (p.anchor), - dkf); - create_denomkey_issue (&p, - &denomkey_issue); - if (GNUNET_OK != - TALER_MINTDB_denomination_key_write (dkf, - &denomkey_issue)) - { - fprintf (stderr, - "Failed to write denomination key information to file `%s'.\n", - dkf); - *ret = GNUNET_SYSERR; - GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); - return; - } - if ( (NULL != auditor_output_file) && - (sizeof (denomkey_issue.issue.properties) != - fwrite (&denomkey_issue.issue.properties, - sizeof (struct TALER_DenominationKeyValidityPS), - 1, - auditor_output_file)) ) - { - fprintf (stderr, - "Failed to write denomination key information to %s: %s\n", - auditorrequestfile, - STRERROR (errno)); - *ret = GNUNET_SYSERR; - return; - } - GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); - p.anchor = GNUNET_TIME_absolute_add (p.anchor, - p.duration_spend); - p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, - p.duration_overlap); - } -} - - -/** - * Update all of the denomination keys of the mint. - * - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -mint_keys_update_denomkeys () -{ - int ok; - - ok = GNUNET_OK; - GNUNET_CONFIGURATION_iterate_sections (kcfg, - &mint_keys_update_cointype, - &ok); - return ok; -} - - -/** - * The main function of the taler-mint-keyup tool. This tool is used - * to create the signing and denomination keys for the mint. It uses - * the long-term offline private key and writes the (additional) key - * files to the respective mint directory (from where they can then be - * copied to the online server). Note that we need (at least) the - * most recent generated previous keys so as to align the validity - * periods. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'d', "mint-dir", "DIR", - "mint directory with keys to update", 1, - &GNUNET_GETOPT_set_filename, &mint_directory}, - TALER_GETOPT_OPTION_HELP ("Setup signing and denomination keys for a Taler mint"), - {'m', "master-key", "FILE", - "master key file (private key)", 1, - &GNUNET_GETOPT_set_filename, &masterkeyfile}, - {'o', "output", "FILE", - "auditor denomination key signing request file to create", 1, - &GNUNET_GETOPT_set_filename, &auditorrequestfile}, - {'t', "time", "TIMESTAMP", - "pretend it is a different time for the update", 0, - &GNUNET_GETOPT_set_string, &pretend_time_str}, - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - struct GNUNET_TIME_Relative lookahead_sign; - struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-mint-keyup", - "WARNING", - NULL)); - - if (GNUNET_GETOPT_run ("taler-mint-keyup", - options, - argc, argv) < 0) - return 1; - if (NULL == mint_directory) - { - fprintf (stderr, - "Mint directory not given\n"); - return 1; - } - if (NULL != pretend_time_str) - { - if (GNUNET_OK != - GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, - &now)) - { - fprintf (stderr, - "timestamp `%s' invalid\n", - pretend_time_str); - return 1; - } - } - else - { - now = GNUNET_TIME_absolute_get (); - } - TALER_round_abs_time (&now); - - kcfg = TALER_config_load (mint_directory); - if (NULL == kcfg) - { - fprintf (stderr, - "Failed to load mint configuration\n"); - return 1; - } - if (NULL == masterkeyfile) - { - fprintf (stderr, - "Master key file not given\n"); - return 1; - } - eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); - if (NULL == eddsa_priv) - { - fprintf (stderr, - "Failed to initialize master key from file `%s'\n", - masterkeyfile); - return 1; - } - master_priv.eddsa_priv = *eddsa_priv; - GNUNET_free (eddsa_priv); - GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv, - &master_public_key.eddsa_pub); - - if (NULL != auditorrequestfile) - { - auditor_output_file = FOPEN (auditorrequestfile, - "w"); - if (NULL == auditor_output_file) - { - fprintf (stderr, - "Failed to open `%s' for writing: %s\n", - auditorrequestfile, - STRERROR (errno)); - return 1; - } - } - - /* check if key from file matches the one from the configuration */ - { - struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_data (kcfg, - "mint", - "master_public_key", - &master_public_key_from_cfg, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "master_public_key"); - return 1; - } - if (0 != - memcmp (&master_public_key, - &master_public_key_from_cfg, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "mint", - "master_public_key", - _("does not match with private key")); - return 1; - } - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - "mint_keys", - "lookahead_sign", - &lookahead_sign)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint_keys", - "lookahead_sign"); - return GNUNET_SYSERR; - } - if (0 == lookahead_sign.rel_value_us) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "mint_keys", - "lookahead_sign", - _("must not be zero")); - return GNUNET_SYSERR; - } - TALER_round_rel_time (&lookahead_sign); - lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, - lookahead_sign); - - - /* finally, do actual work */ - if (GNUNET_OK != mint_keys_update_signkeys ()) - return 1; - - if (GNUNET_OK != mint_keys_update_denomkeys ()) - return 1; - if (NULL != auditor_output_file) - { - FCLOSE (auditor_output_file); - auditor_output_file = NULL; - } - return 0; -} - -/* end of taler-mint-keyup.c */ diff --git a/src/mint-tools/taler-mint-reservemod.c b/src/mint-tools/taler-mint-reservemod.c deleted file mode 100644 index 38d27054a..000000000 --- a/src/mint-tools/taler-mint-reservemod.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-reservemod.c - * @brief Modify reserves. Allows manipulation of reserve balances. - * @author Florian Dold - * @author Benedikt Mueller - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <libpq-fe.h> -#include <jansson.h> -#include "taler_mintdb_plugin.h" - -/** - * Director of the mint, containing the keys. - */ -static char *mint_directory; - -/** - * Handle to the mint's configuration - */ -static struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Our DB plugin. - */ -static struct TALER_MINTDB_Plugin *plugin; - - -/** - * The main function of the reservemod tool - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - char *reserve_pub_str = NULL; - char *add_str = NULL; - struct TALER_Amount add_value; - char *details = NULL; - json_t *jdetails; - json_error_t error; - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_MINTDB_Session *session; - const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'a', "add", "DENOM", - "value to add", 1, - &GNUNET_GETOPT_set_string, &add_str}, - {'d', "mint-dir", "DIR", - "mint directory with keys to update", 1, - &GNUNET_GETOPT_set_filename, &mint_directory}, - {'D', "details", "JSON", - "details about the bank transaction which justify why we add this amount", 1, - &GNUNET_GETOPT_set_string, &details}, - TALER_GETOPT_OPTION_HELP ("Deposit funds into a Taler reserve"), - {'R', "reserve", "KEY", - "reserve (public key) to modify", 1, - &GNUNET_GETOPT_set_string, &reserve_pub_str}, - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - int ret; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-mint-reservemod", - "WARNING", - NULL)); - - if (GNUNET_GETOPT_run ("taler-mint-reservemod", - options, - argc, argv) < 0) - return 1; - if (NULL == mint_directory) - { - fprintf (stderr, - "Mint directory not given\n"); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (details); - GNUNET_free_non_null (reserve_pub_str); - return 1; - } - if ((NULL == reserve_pub_str) || - (GNUNET_OK != - GNUNET_STRINGS_string_to_data (reserve_pub_str, - strlen (reserve_pub_str), - &reserve_pub, - sizeof (struct TALER_ReservePublicKeyP)))) - { - fprintf (stderr, - "Parsing reserve key invalid\n"); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (details); - GNUNET_free_non_null (reserve_pub_str); - return 1; - } - if ( (NULL == add_str) || - (GNUNET_OK != - TALER_string_to_amount (add_str, - &add_value)) ) - { - fprintf (stderr, - "Failed to parse currency amount `%s'\n", - add_str); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (details); - GNUNET_free_non_null (reserve_pub_str); - return 1; - } - - if (NULL == details) - { - fprintf (stderr, - "No wiring details given (justification required)\n"); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (reserve_pub_str); - return 1; - } - - cfg = TALER_config_load (mint_directory); - if (NULL == cfg) - { - fprintf (stderr, - "Failed to load mint configuration\n"); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (details); - GNUNET_free_non_null (reserve_pub_str); - return 1; - } - ret = 1; - if (NULL == - (plugin = TALER_MINTDB_plugin_load (cfg))) - { - fprintf (stderr, - "Failed to initialize database plugin.\n"); - goto cleanup; - } - - session = plugin->get_session (plugin->cls, - GNUNET_NO); - if (NULL == session) - { - fprintf (stderr, - "Failed to initialize DB session\n"); - goto cleanup; - } - jdetails = json_loads (details, - JSON_REJECT_DUPLICATES, - &error); - if (NULL == jdetails) - { - fprintf (stderr, - "Failed to parse JSON transaction details `%s': %s (%s)\n", - details, - error.text, - error.source); - goto cleanup; - } - /* FIXME: maybe allow passing timestamp via command-line? */ - ret = plugin->reserves_in_insert (plugin->cls, - session, - &reserve_pub, - &add_value, - GNUNET_TIME_absolute_get (), - jdetails); - json_decref (jdetails); - if (GNUNET_SYSERR == ret) - { - fprintf (stderr, - "Failed to update reserve.\n"); - goto cleanup; - } - if (GNUNET_NO == ret) - { - fprintf (stderr, - "Record exists, reserve not updated.\n"); - } - ret = 0; - cleanup: - if (NULL != plugin) - TALER_MINTDB_plugin_unload (plugin); - if (NULL != cfg) - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free_non_null (add_str); - GNUNET_free_non_null (details); - GNUNET_free_non_null (reserve_pub_str); - return ret; -} - -/* end taler-mint-reservemod.c */ diff --git a/src/mint-tools/taler-mint-sepa.c b/src/mint-tools/taler-mint-sepa.c deleted file mode 100644 index e66db541e..000000000 --- a/src/mint-tools/taler-mint-sepa.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-sepa.c - * @brief Create signed response for /wire/sepa requests. - * @author Christian Grothoff - */ -#include <platform.h> -#include <jansson.h> -#include "taler_crypto_lib.h" -#include "taler_signatures.h" - - -/** - * Filename of the master private key. - */ -static char *masterkeyfile; - -/** - * Account holder name. - */ -static char *sepa_name; - -/** - * IBAN number. - */ -static char *iban; - -/** - * BIC number. - */ -static char *bic; - -/** - * Where to write the result. - */ -static char *output_filename; - - -/** - * The main function of the taler-mint-sepa tool. This tool is used - * to sign the SEPA bank account details using the master key. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'b', "bic", "BICCODE", - "bank BIC code", 1, - &GNUNET_GETOPT_set_string, &bic}, - {'i', "iban", "IBAN", - "IBAN number of the account", 1, - &GNUNET_GETOPT_set_string, &iban}, - {'m', "master-key", "FILE", - "master key file (private key)", 1, - &GNUNET_GETOPT_set_filename, &masterkeyfile}, - {'n', "name", "NAME", - "name of the account holder", 1, - &GNUNET_GETOPT_set_string, &sepa_name}, - {'o', "output", "FILE", - "where to write the result", 1, - &GNUNET_GETOPT_set_filename, &output_filename}, - TALER_GETOPT_OPTION_HELP ("Setup /wire/sepa response"), - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; - struct TALER_MasterWireSepaDetailsPS wsd; - struct TALER_MasterSignatureP sig; - struct GNUNET_HashContext *hc; - json_t *reply; - char *json_str; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-mint-sepa", - "WARNING", - NULL)); - - if (GNUNET_GETOPT_run ("taler-mint-sepa", - options, - argc, argv) < 0) - return 1; - if (NULL == masterkeyfile) - { - fprintf (stderr, - "Master key file not given\n"); - return 1; - } - eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); - if (NULL == eddsa_priv) - { - fprintf (stderr, - "Failed to initialize master key from file `%s'\n", - masterkeyfile); - return 1; - } - - /* Compute message to sign */ - hc = GNUNET_CRYPTO_hash_context_start (); - GNUNET_CRYPTO_hash_context_read (hc, - sepa_name, - strlen (sepa_name) + 1); - GNUNET_CRYPTO_hash_context_read (hc, - iban, - strlen (iban) + 1); - GNUNET_CRYPTO_hash_context_read (hc, - bic, - strlen (bic) + 1); - wsd.purpose.size = htonl (sizeof (wsd)); - wsd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS); - GNUNET_CRYPTO_hash_context_finish (hc, - &wsd.h_sepa_details); - GNUNET_CRYPTO_eddsa_sign (eddsa_priv, - &wsd.purpose, - &sig.eddsa_signature); - GNUNET_free (eddsa_priv); - - /* build JSON message */ - reply = json_pack ("{s:s, s:s, s:s, s:o}", - "receiver_name", sepa_name, - "iban", iban, - "bic", bic, - "sig", TALER_json_from_data (&sig, - sizeof (sig))); - GNUNET_assert (NULL != reply); - - /* dump result to stdout */ - json_str = json_dumps (reply, JSON_INDENT(2)); - GNUNET_assert (NULL != json_str); - - if (NULL != output_filename) - { - fclose (stdout); - stdout = fopen (output_filename, - "w+"); - } - fprintf (stdout, - "%s", - json_str); - fflush (stdout); - free (json_str); - return 0; -} - -/* end of taler-mint-sepa.c */ diff --git a/src/mint/.gitignore b/src/mint/.gitignore deleted file mode 100644 index a2e71d5da..000000000 --- a/src/mint/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -taler-mint-dbinit -taler-mint-keycheck -taler-mint-keyup -taler-mint-pursemod -taler-mint-reservemod -taler-mint-httpd
\ No newline at end of file diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am deleted file mode 100644 index 8e2eae77b..000000000 --- a/src/mint/Makefile.am +++ /dev/null @@ -1,59 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -bin_PROGRAMS = \ - taler-mint-aggregator \ - taler-mint-httpd - -taler_mint_aggregator_SOURCES = \ - taler-mint-aggregator.c -taler_mint_aggregator_LDADD = \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/wire/libtalerwire.la \ - $(top_builddir)/src/mintdb/libtalermintdb.la \ - -ljansson \ - -lgnunetutil - -taler_mint_httpd_SOURCES = \ - taler-mint-httpd.c taler-mint-httpd.h \ - taler-mint-httpd_admin.c taler-mint-httpd_admin.h \ - taler-mint-httpd_db.c taler-mint-httpd_db.h \ - taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \ - taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \ - taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \ - taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \ - taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h \ - taler-mint-httpd_reserve.c taler-mint-httpd_reserve.h \ - taler-mint-httpd_responses.c taler-mint-httpd_responses.h \ - taler-mint-httpd_tracking.c taler-mint-httpd_tracking.h \ - taler-mint-httpd_wire.c taler-mint-httpd_wire.h \ - taler-mint-httpd_validation.c taler-mint-httpd_validation.h -taler_mint_httpd_LDADD = \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/mintdb/libtalermintdb.la \ - -lmicrohttpd \ - -ljansson \ - -lgnunetutil \ - -lpthread - -if HAVE_DEVELOPER -taler_mint_httpd_SOURCES += \ - taler-mint-httpd_test.c taler-mint-httpd_test.h -endif - -check_SCRIPTS = \ - test_taler_mint_httpd.sh - -if HAVE_EXPENSIVE_TESTS -check_SCRIPTS += \ - test_taler_mint_httpd_afl.sh -endif - -TESTS = $(check_SCRIPTS) diff --git a/src/mint/taler-mint-aggregator.c b/src/mint/taler-mint-aggregator.c deleted file mode 100644 index 5e05c8673..000000000 --- a/src/mint/taler-mint-aggregator.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-aggregator.c - * @brief Process that aggregates outgoing transactions and executes them - * @author Christian Grothoff - * - * TODO: - * - simplify global_ret: make it a global! - * - handle shutdown more nicely (call 'cancel' method on wire transfers) - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <pthread.h> -#include "taler_mintdb_lib.h" -#include "taler_mintdb_plugin.h" -#include "taler_wire_lib.h" - -/** - * Which currency is used by this mint? - */ -static char *mint_currency_string; - -/** - * Which wireformat should be supported by this aggregator? - */ -static char *mint_wireformat; - -/** - * Base directory of the mint (global) - */ -static char *mint_directory; - -/** - * The mint's configuration (global) - */ -static struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Our DB plugin. - */ -static struct TALER_MINTDB_Plugin *db_plugin; - -/** - * Our wire plugin. - */ -static struct TALER_WIRE_Plugin *wire_plugin; - -/** - * Task for the main #run() function. - */ -static struct GNUNET_SCHEDULER_Task *task; - -/** - * Limit on the number of transactions we aggregate at once. Note - * that the limit must be big enough to ensure that when transactions - * of the smallest possible unit are aggregated, they do surpass the - * "tiny" threshold beyond which we never trigger a wire transaction! - * - * TODO: make configurable (via config file or command line option) - */ -static unsigned int aggregation_limit = 10000; - - -/** - * Load configuration parameters for the mint - * server into the corresponding global variables. - * - * @param mint_directory the mint's directory - * @return #GNUNET_OK on success - */ -static int -mint_serve_process_config (const char *mint_directory) -{ - char *type; - - cfg = TALER_config_load (mint_directory); - if (NULL == cfg) - { - fprintf (stderr, - "Failed to load mint configuration\n"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "currency", - &mint_currency_string)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "currency"); - return GNUNET_SYSERR; - } - if (strlen (mint_currency_string) >= TALER_CURRENCY_LEN) - { - fprintf (stderr, - "Currency `%s' longer than the allowed limit of %u characters.", - mint_currency_string, - (unsigned int) TALER_CURRENCY_LEN); - return GNUNET_SYSERR; - } - if (NULL != mint_wireformat) - GNUNET_CONFIGURATION_set_value_string (cfg, - "mint", - "wireformat", - mint_wireformat); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "wireformat", - &type)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "wireformat"); - return GNUNET_SYSERR; - } - - if (NULL == - (db_plugin = TALER_MINTDB_plugin_load (cfg))) - { - fprintf (stderr, - "Failed to initialize DB subsystem\n"); - GNUNET_free (type); - return GNUNET_SYSERR; - } - - if (NULL == - (wire_plugin = TALER_WIRE_plugin_load (cfg, - type))) - { - fprintf (stderr, - "Failed to load wire plugin for `%s'\n", - type); - GNUNET_free (type); - return GNUNET_SYSERR; - } - GNUNET_free (type); - - return GNUNET_OK; -} - - -/** - * Information about one aggregation process to - * be executed. - */ -struct AggregationUnit -{ - /** - * Public key of the merchant. - */ - struct TALER_MerchantPublicKeyP merchant_pub; - - /** - * Total amount to be transferred. - */ - struct TALER_Amount total_amount; - - /** - * Hash of @e wire. - */ - struct GNUNET_HashCode h_wire; - - /** - * Wire transfer identifier we use. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Row ID of the transaction that started it all. - */ - unsigned long long row_id; - - /** - * The current time. - */ - struct GNUNET_TIME_Absolute execution_time; - - /** - * Wire details of the merchant. - */ - json_t *wire; - - /** - * Database session for all of our transactions. - */ - struct TALER_MINTDB_Session *session; - - /** - * Wire preparation handle. - */ - struct TALER_WIRE_PrepareHandle *ph; - - /** - * Array of #aggregation_limit row_ids from the - * aggregation. - */ - unsigned long long *additional_rows; - - /** - * Pointer to global return value. Closure for #run(). - */ - int *global_ret; - - /** - * Offset specifying how many #additional_rows are in use. - */ - unsigned int rows_offset; - - /** - * Set to #GNUNET_YES if we have to abort due to failure. - */ - int failed; - -}; - - -/** - * Function called with details about deposits that have been made, - * with the goal of executing the corresponding wire transaction. - * - * @param cls closure with the `struct AggregationUnit` - * @param row_id identifies database entry - * @param merchant_pub public key of the merchant - * @param coin_pub public key of the coin - * @param amount_with_fee amount that was deposited including fee - * @param deposit_fee amount the mint gets to keep as transaction fees - * @param transaction_id unique transaction ID chosen by the merchant - * @param h_contract hash of the contract between merchant and customer - * @param wire_deadline by which the merchant adviced that he would like the - * wire transfer to be executed - * @param wire wire details for the merchant - * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop - */ -static int -deposit_cb (void *cls, - unsigned long long row_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - uint64_t transaction_id, - const struct GNUNET_HashCode *h_contract, - struct GNUNET_TIME_Absolute wire_deadline, - const json_t *wire) -{ - struct AggregationUnit *au = cls; - - au->merchant_pub = *merchant_pub; - if (GNUNET_OK != - TALER_amount_subtract (&au->total_amount, - amount_with_fee, - deposit_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Fatally malformed record at %llu\n", - row_id); - return GNUNET_SYSERR; - } - au->row_id = row_id; - au->wire = (json_t *) wire; - au->execution_time = GNUNET_TIME_absolute_get (); - TALER_hash_json (au->wire, - &au->h_wire); - json_incref (au->wire); - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &au->wtid, - sizeof (au->wtid)); - if (GNUNET_OK != - db_plugin->insert_aggregation_tracking (db_plugin->cls, - au->session, - &au->wtid, - merchant_pub, - &au->h_wire, - h_contract, - transaction_id, - au->execution_time, - coin_pub, - amount_with_fee, - deposit_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - db_plugin->mark_deposit_done (db_plugin->cls, - au->session, - row_id)) - { - GNUNET_break (0); - au->failed = GNUNET_YES; - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - - -/** - * Function called with details about another deposit we - * can aggregate into an existing aggregation unit. - * - * @param cls closure with the `struct AggregationUnit` - * @param row_id identifies database entry - * @param merchant_pub public key of the merchant - * @param coin_pub public key of the coin - * @param amount_with_fee amount that was deposited including fee - * @param deposit_fee amount the mint gets to keep as transaction fees - * @param transaction_id unique transaction ID chosen by the merchant - * @param h_contract hash of the contract between merchant and customer - * @param wire_deadline by which the merchant adviced that he would like the - * wire transfer to be executed - * @param wire wire details for the merchant - * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop - */ -static int -aggregate_cb (void *cls, - unsigned long long row_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - uint64_t transaction_id, - const struct GNUNET_HashCode *h_contract, - struct GNUNET_TIME_Absolute wire_deadline, - const json_t *wire) -{ - struct AggregationUnit *au = cls; - struct TALER_Amount delta; - - GNUNET_break (0 == - memcmp (&au->merchant_pub, - merchant_pub, - sizeof (struct TALER_MerchantPublicKeyP))); - /* compute contribution of this coin after fees */ - if (GNUNET_OK != - TALER_amount_subtract (&delta, - amount_with_fee, - deposit_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Fatally malformed record at %llu\n", - row_id); - return GNUNET_SYSERR; - } - /* add to total */ - if (GNUNET_OK != - TALER_amount_add (&au->total_amount, - &au->total_amount, - &delta)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Overflow or currency incompatibility during aggregation at %llu\n", - row_id); - /* Skip this one, but keep going! */ - return GNUNET_OK; - } - if (au->rows_offset >= aggregation_limit) - { - /* Bug: we asked for at most #aggregation_limit results! */ - GNUNET_break (0); - /* Skip this one, but keep going. */ - return GNUNET_OK; - } - if (NULL == au->additional_rows) - au->additional_rows = GNUNET_new_array (aggregation_limit, - unsigned long long); - /* "append" to our list of rows */ - au->additional_rows[au->rows_offset++] = row_id; - /* insert into aggregation tracking table */ - if (GNUNET_OK != - db_plugin->insert_aggregation_tracking (db_plugin->cls, - au->session, - &au->wtid, - merchant_pub, - &au->h_wire, - h_contract, - transaction_id, - au->execution_time, - coin_pub, - amount_with_fee, - deposit_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - db_plugin->mark_deposit_done (db_plugin->cls, - au->session, - row_id)) - { - GNUNET_break (0); - au->failed = GNUNET_YES; - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function to be called with the prepared transfer data. - * - * @param cls closure with the `struct AggregationUnit` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, - const char *buf, - size_t buf_size); - - -/** - * Main work function that queries the DB and aggregates transactions - * into larger wire transfers. - * - * @param cls pointer to an `int` which we will return from main() - * @param tc scheduler context - */ -static void -run_aggregation (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - int *global_ret = cls; - struct TALER_MINTDB_Session *session; - struct AggregationUnit *au; - unsigned int i; - int ret; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - if (NULL == (session = db_plugin->get_session (db_plugin->cls, - GNUNET_NO))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to obtain database session!\n"); - *global_ret = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - db_plugin->start (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to start database transaction!\n"); - *global_ret = GNUNET_SYSERR; - return; - } - au = GNUNET_new (struct AggregationUnit); - au->session = session; - ret = db_plugin->get_ready_deposit (db_plugin->cls, - session, - &deposit_cb, - au); - if (GNUNET_OK != ret) - { - GNUNET_free (au); - db_plugin->rollback (db_plugin->cls, - session); - if (0 != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to execute deposit iteration!\n"); - *global_ret = GNUNET_SYSERR; - return; - } - /* nothing to do, sleep for a minute and try again */ - task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, - &run_aggregation, - global_ret); - return; - } - /* Now try to find other deposits to aggregate */ - ret = db_plugin->iterate_matching_deposits (db_plugin->cls, - session, - &au->h_wire, - &au->merchant_pub, - &aggregate_cb, - au, - aggregation_limit); - if ( (GNUNET_SYSERR == ret) || - (GNUNET_YES == au->failed) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to execute deposit iteration!\n"); - GNUNET_free_non_null (au->additional_rows); - GNUNET_free (au); - db_plugin->rollback (db_plugin->cls, - session); - *global_ret = GNUNET_SYSERR; - return; - } - /* Round to the unit supported by the wire transfer method */ - GNUNET_assert (GNUNET_SYSERR != - wire_plugin->amount_round (wire_plugin->cls, - &au->total_amount)); - /* Check if after rounding down, we still have an amount to transfer */ - if ( (0 == au->total_amount.value) && - (0 == au->total_amount.fraction) ) - { - /* Rollback ongoing transaction, as we will not use the respective - WTID and thus need to remove the tracking data */ - db_plugin->rollback (db_plugin->cls, - session); - /* Start another transaction to mark all* of the selected deposits - *as minor! */ - if (GNUNET_OK != - db_plugin->start (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to start database transaction!\n"); - *global_ret = GNUNET_SYSERR; - GNUNET_free_non_null (au->additional_rows); - GNUNET_free (au); - return; - } - /* Mark transactions by row_id as minor */ - ret = GNUNET_OK; - if (GNUNET_OK != - db_plugin->mark_deposit_tiny (db_plugin->cls, - session, - au->row_id)) - ret = GNUNET_SYSERR; - else - for (i=0;i<au->rows_offset;i++) - if (GNUNET_OK != - db_plugin->mark_deposit_tiny (db_plugin->cls, - session, - au->additional_rows[i])) - ret = GNUNET_SYSERR; - /* commit */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit database transaction!\n"); - } - GNUNET_free_non_null (au->additional_rows); - GNUNET_free (au); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - au->global_ret = global_ret; - au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls, - au->wire, - &au->total_amount, - &au->wtid, - &prepare_cb, - au); - /* FIXME: currently we have no clean-up plan on - shutdown to call prepare_wire_transfer_cancel! - Maybe make 'au' global? */ - if (NULL == au->ph) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - session); - GNUNET_free_non_null (au->additional_rows); - GNUNET_free (au); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - /* otherwise we continue with #prepare_cb(), see below */ -} - - -/** - * Execute the wire transfers that we have committed to - * do. - * - * @param cls pointer to an `int` which we will return from main() - * @param tc scheduler context - */ -static void -run_transfers (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Function to be called with the prepared transfer data. - * - * @param cls closure with the `struct AggregationUnit` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, - const char *buf, - size_t buf_size) -{ - struct AggregationUnit *au = cls; - int *global_ret = au->global_ret; - struct TALER_MINTDB_Session *session = au->session; - - GNUNET_free_non_null (au->additional_rows); - GNUNET_free (au); - if (NULL == buf) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - session); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - - /* Commit our intention to execute the wire transfer! */ - if (GNUNET_OK != - db_plugin->wire_prepare_data_insert (db_plugin->cls, - session, - mint_wireformat, - buf, - buf_size)) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - session); - /* start again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - - /* Now we can finally commit the overall transaction, as we are - again consistent if all of this passes. */ - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to commit database transaction!\n"); - /* try again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - - /* run alternative task: actually do wire transfer! */ - task = GNUNET_SCHEDULER_add_now (&run_transfers, - &global_ret); -} - - -/** - * Data we keep to #run_transfers(). - */ -struct WirePrepareData -{ - - /** - * Database session for all of our transactions. - */ - struct TALER_MINTDB_Session *session; - - /** - * Wire execution handle. - */ - struct TALER_WIRE_ExecuteHandle *eh; - - /** - * Pointer to global return value. Closure for #run(). - */ - int *global_ret; - - - /** - * Row ID of the transfer. - */ - unsigned long long row_id; - -}; - - -/** - * Function called with the result from the execute step. - * - * @param cls closure with the `struct WirePrepareData` - * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure - * @param emsg NULL on success, otherwise an error message - */ -static void -wire_confirm_cb (void *cls, - int success, - const char *emsg) -{ - struct WirePrepareData *wpd = cls; - int *global_ret = wpd->global_ret; - struct TALER_MINTDB_Session *session = wpd->session; - - wpd->eh = NULL; - if (GNUNET_SYSERR == success) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire transaction failed: %s\n", - emsg); - db_plugin->rollback (db_plugin->cls, - session); - *global_ret = GNUNET_SYSERR; - GNUNET_free (wpd); - return; - } - if (GNUNET_OK != - db_plugin->wire_prepare_data_mark_finished (db_plugin->cls, - session, - wpd->row_id)) - { - GNUNET_break (0); /* why!? */ - db_plugin->rollback (db_plugin->cls, - session); - *global_ret = GNUNET_SYSERR; - GNUNET_free (wpd); - return; - } - GNUNET_free (wpd); - if (GNUNET_OK != - db_plugin->commit (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to commit database transaction!\n"); - /* try again */ - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - return; - } - /* continue with #run_transfers(), just to guard - against the unlikely case that there are more. */ - task = GNUNET_SCHEDULER_add_now (&run_transfers, - &global_ret); - -} - - -/** - * Callback with data about a prepared transaction. - * - * @param cls closure with the `struct WirePrepareData` - * @param rowid row identifier used to mark prepared transaction as done - * @param buf transaction data that was persisted, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -wire_prepare_cb (void *cls, - unsigned long long rowid, - const char *buf, - size_t buf_size) -{ - struct WirePrepareData *wpd = cls; - int *global_ret = wpd->global_ret; - - wpd->row_id = rowid; - wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls, - buf, - buf_size, - &wire_confirm_cb, - wpd); - /* FIXME: currently we have no clean-up plan on - shutdown to call execute_wire_transfer_cancel! - Maybe make 'wpd' global? */ - if (NULL == wpd->eh) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - wpd->session); - *global_ret = GNUNET_SYSERR; - GNUNET_free (wpd); - return; - } -} - - -/** - * Execute the wire transfers that we have committed to - * do. - * - * @param cls pointer to an `int` which we will return from main() - * @param tc scheduler context - */ -static void -run_transfers (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - int *global_ret = cls; - int ret; - struct WirePrepareData *wpd; - struct TALER_MINTDB_Session *session; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - if (NULL == (session = db_plugin->get_session (db_plugin->cls, - GNUNET_NO))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to obtain database session!\n"); - *global_ret = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - db_plugin->start (db_plugin->cls, - session)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to start database transaction!\n"); - *global_ret = GNUNET_SYSERR; - return; - } - wpd = GNUNET_new (struct WirePrepareData); - wpd->session = session; - wpd->global_ret = global_ret; - ret = db_plugin->wire_prepare_data_get (db_plugin->cls, - session, - mint_wireformat, - &wire_prepare_cb, - wpd); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); /* why? how to best recover? */ - db_plugin->rollback (db_plugin->cls, - session); - *global_ret = GNUNET_SYSERR; - GNUNET_free (wpd); - return; - } - if (GNUNET_NO == ret) - { - /* no more prepared wire transfers, go back to aggregation! */ - db_plugin->rollback (db_plugin->cls, - session); - task = GNUNET_SCHEDULER_add_now (&run_aggregation, - global_ret); - GNUNET_free (wpd); - return; - } - /* otherwise, continues in #wire_prepare_cb() */ -} - - -/** - * The main function of the taler-mint-httpd server ("the mint"). - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'d', "mint-dir", "DIR", - "mint directory with configuration and keys for operating the mint", 1, - &GNUNET_GETOPT_set_filename, &mint_directory}, - {'f', "format", "WIREFORMAT", - "wireformat to use, overrides WIREFORMAT option in [mint] section", 1, - &GNUNET_GETOPT_set_filename, &mint_wireformat}, - TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"), - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - int ret = GNUNET_OK; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-mint-aggregator", - "INFO", - NULL)); - if (0 >= - GNUNET_GETOPT_run ("taler-mint-aggregator", - options, - argc, argv)) - return 1; - if (NULL == mint_directory) - { - fprintf (stderr, - "Mint directory not specified\n"); - return 1; - } - if (GNUNET_OK != - mint_serve_process_config (mint_directory)) - { - return 1; - } - - GNUNET_SCHEDULER_run (&run_transfers, &ret); - - TALER_MINTDB_plugin_unload (db_plugin); - TALER_WIRE_plugin_unload (wire_plugin); - return (GNUNET_SYSERR == ret) ? 1 : 0; -} - -/* end of taler-mint-aggregator.c */ diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c deleted file mode 100644 index 5d6aa0589..000000000 --- a/src/mint/taler-mint-httpd.c +++ /dev/null @@ -1,749 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd.c - * @brief Serve the HTTP interface of the mint - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_mhd.h" -#include "taler-mint-httpd_admin.h" -#include "taler-mint-httpd_deposit.h" -#include "taler-mint-httpd_reserve.h" -#include "taler-mint-httpd_wire.h" -#include "taler-mint-httpd_refresh.h" -#include "taler-mint-httpd_tracking.h" -#include "taler-mint-httpd_keystate.h" -#if HAVE_DEVELOPER -#include "taler-mint-httpd_test.h" -#endif -#include "taler_mintdb_plugin.h" -#include "taler-mint-httpd_validation.h" - -/** - * Which currency is used by this mint? - */ -char *TMH_mint_currency_string; - -/** - * Should we return "Connection: close" in each response? - */ -int TMH_mint_connection_close; - -/** - * Base directory of the mint (global) - */ -char *TMH_mint_directory; - -/** - * The mint's configuration (global) - */ -struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Master public key (according to the - * configuration in the mint directory). - */ -struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key; - -/** - * Our DB plugin. - */ -struct TALER_MINTDB_Plugin *TMH_plugin; - -/** - * Are we running in test mode? - */ -int TMH_test_mode; - -/** - * Default timeout in seconds for HTTP requests. - */ -static unsigned int connection_timeout = 30; - -/** - * The HTTP Daemon. - */ -static struct MHD_Daemon *mydaemon; - -/** - * Port to run the daemon on. - */ -static uint16_t serve_port; - - -/** - * Function called whenever MHD is done with a request. If the - * request was a POST, we may have stored a `struct Buffer *` in the - * @a con_cls that might still need to be cleaned up. Call the - * respective function to free the memory. - * - * @param cls client-defined closure - * @param connection connection handle - * @param con_cls value as set by the last call to - * the #MHD_AccessHandlerCallback - * @param toe reason for request termination - * @see #MHD_OPTION_NOTIFY_COMPLETED - * @ingroup request - */ -static void -handle_mhd_completion_callback (void *cls, - struct MHD_Connection *connection, - void **con_cls, - enum MHD_RequestTerminationCode toe) -{ - if (NULL == *con_cls) - return; - TMH_PARSE_post_cleanup_callback (*con_cls); - *con_cls = NULL; -} - - -/** - * Handle a request coming from libmicrohttpd. - * - * @param cls closure for MHD daemon (unused) - * @param connection the connection - * @param url the requested url - * @param method the method (POST, GET, ...) - * @param version HTTP version (ignored) - * @param upload_data request data - * @param upload_data_size size of @a upload_data in bytes - * @param con_cls closure for request (a `struct Buffer *`) - * @return MHD result code - */ -static int -handle_mhd_request (void *cls, - struct MHD_Connection *connection, - const char *url, - const char *method, - const char *version, - const char *upload_data, - size_t *upload_data_size, - void **con_cls) -{ - static struct TMH_RequestHandler handlers[] = - { - /* Landing page, tell humans to go away. */ - { "/", MHD_HTTP_METHOD_GET, "text/plain", - "Hello, I'm the Taler mint. This HTTP server is not for humans.\n", 0, - &TMH_MHD_handler_static_response, MHD_HTTP_OK }, - /* /robots.txt: disallow everything */ - { "/robots.txt", MHD_HTTP_METHOD_GET, "text/plain", - "User-agent: *\nDisallow: /\n", 0, - &TMH_MHD_handler_static_response, MHD_HTTP_OK }, - /* AGPL licensing page, redirect to source. As per the AGPL-license, - every deployment is required to offer the user a download of the - source. We make this easy by including a redirect to the source - here. */ - { "/agpl", MHD_HTTP_METHOD_GET, "text/plain", - NULL, 0, - &TMH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND }, - - /* Return key material and fundamental properties for this mint */ - { "/keys", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_KS_handler_keys, MHD_HTTP_OK }, - { "/keys", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - /* Requests for wiring information */ - { "/wire", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_WIRE_handler_wire, MHD_HTTP_OK }, - { "/wire", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/wire/test", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_WIRE_handler_wire_test, MHD_HTTP_FOUND }, - { "/wire/test", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/wire/sepa", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_WIRE_handler_wire_sepa, MHD_HTTP_OK }, - { "/wire/sepa", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - /* Withdrawing coins / interaction with reserves */ - { "/reserve/status", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_RESERVE_handler_reserve_status, MHD_HTTP_OK }, - { "/reserve/status", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/reserve/withdraw", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_RESERVE_handler_reserve_withdraw, MHD_HTTP_OK }, - { "/reserve/withdraw", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - /* Depositing coins */ - { "/deposit", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_DEPOSIT_handler_deposit, MHD_HTTP_OK }, - { "/deposit", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - /* Dealing with change */ - { "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_REFRESH_handler_refresh_melt, MHD_HTTP_OK }, - { "/refresh/melt", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK }, - { "/refresh/reveal", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_REFRESH_handler_refresh_reveal, MHD_HTTP_OK }, - { "/refresh/reveal", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/refresh/link", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_REFRESH_handler_refresh_link, MHD_HTTP_OK }, - { "/refresh/link", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - /* FIXME: maybe conditionally compile these? */ - { "/admin/add/incoming", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_ADMIN_handler_admin_add_incoming, MHD_HTTP_OK }, - { "/admin/add/incoming", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/wire/deposits", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_TRACKING_handler_wire_deposits, MHD_HTTP_OK }, - { "/wire/deposits", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - { "/deposit/wtid", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TRACKING_handler_deposit_wtid, MHD_HTTP_OK }, - { "/deposit/wtid", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - -#if HAVE_DEVELOPER - /* Client crypto-interoperability test functions */ - { "/test", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test, MHD_HTTP_OK }, - { "/test", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/base32", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_base32, MHD_HTTP_OK }, - { "/test/base32", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/encrypt", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_encrypt, MHD_HTTP_OK }, - { "/test/encrypt", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/hkdf", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_hkdf, MHD_HTTP_OK }, - { "/test/hkdf", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/ecdhe", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_ecdhe, MHD_HTTP_OK }, - { "/test/ecdhe", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/eddsa", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_eddsa, MHD_HTTP_OK }, - { "/test/eddsa", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/rsa/get", MHD_HTTP_METHOD_GET, "application/json", - NULL, 0, - &TMH_TEST_handler_test_rsa_get, MHD_HTTP_OK }, - { "/test/rsa/get", NULL, "text/plain", - "Only GET is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/rsa/sign", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_rsa_sign, MHD_HTTP_OK }, - { "/test/rsa/sign", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - - { "/test/transfer", MHD_HTTP_METHOD_POST, "application/json", - NULL, 0, - &TMH_TEST_handler_test_transfer, MHD_HTTP_OK }, - { "/test/transfer", NULL, "text/plain", - "Only POST is allowed", 0, - &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, -#endif - - { NULL, NULL, NULL, NULL, 0, 0 } - }; - static struct TMH_RequestHandler h404 = - { - "", NULL, "text/html", - "<html><title>404: not found</title></html>", 0, - &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND - }; - struct TMH_RequestHandler *rh; - unsigned int i; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling request for URL '%s'\n", - url); - for (i=0;NULL != handlers[i].url;i++) - { - rh = &handlers[i]; - if ( (0 == strcasecmp (url, - rh->url)) && - ( (NULL == rh->method) || - (0 == strcasecmp (method, - rh->method)) ) ) - return rh->handler (rh, - connection, - con_cls, - upload_data, - upload_data_size); - } - return TMH_MHD_handler_static_response (&h404, - connection, - con_cls, - upload_data, - upload_data_size); -} - - -/** - * Load configuration parameters for the mint - * server into the corresponding global variables. - * - * @param mint_directory the mint's directory - * @return #GNUNET_OK on success - */ -static int -mint_serve_process_config (const char *mint_directory) -{ - unsigned long long port; - char *TMH_master_public_key_str; - - cfg = TALER_config_load (mint_directory); - if (NULL == cfg) - { - fprintf (stderr, - "Failed to load mint configuration\n"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "currency", - &TMH_mint_currency_string)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "currency"); - return GNUNET_SYSERR; - } - if (strlen (TMH_mint_currency_string) >= TALER_CURRENCY_LEN) - { - fprintf (stderr, - "Currency `%s' longer than the allowed limit of %u characters.", - TMH_mint_currency_string, - (unsigned int) TALER_CURRENCY_LEN); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TMH_VALIDATION_init (cfg)) - return GNUNET_SYSERR; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "master_public_key", - &TMH_master_public_key_str)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "master_public_key"); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_public_key_from_string (TMH_master_public_key_str, - strlen (TMH_master_public_key_str), - &TMH_master_public_key)) - { - fprintf (stderr, - "Invalid master public key given in mint configuration."); - GNUNET_free (TMH_master_public_key_str); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - GNUNET_free (TMH_master_public_key_str); - - if (NULL == - (TMH_plugin = TALER_MINTDB_plugin_load (cfg))) - { - fprintf (stderr, - "Failed to initialize DB subsystem\n"); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (cfg, - "mint", - "TESTRUN")) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Running in TEST mode! Database contents will not persist!\n"); - TMH_test_mode = GNUNET_YES; - TMH_plugin->create_tables (TMH_plugin->cls, - GNUNET_YES); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "mint", - "port", - &port)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "mint", - "port", - "port number required"); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - - if ( (0 == port) || - (port > UINT16_MAX) ) - { - fprintf (stderr, - "Invalid configuration (value out of range): %llu is not a valid port\n", - port); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - serve_port = (uint16_t) port; - - return GNUNET_OK; -} - - -/* Developer logic for supporting the `-f' option. */ -#if HAVE_DEVELOPER - -/** - * Option `-f' (specifies an input file to give to the HTTP server). - */ -static char *input_filename; - - -/** - * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename - * as the input for the request. If launching the client worked, - * run the #TMH_KS_loop() event loop as usual. - * - * @return #GNUNET_OK - */ -static int -run_fake_client () -{ - pid_t cld; - char ports[6]; - int fd; - int ret; - int status; - - fd = open (input_filename, O_RDONLY); - if (-1 == fd) - { - fprintf (stderr, - "Failed to open `%s': %s\n", - input_filename, - strerror (errno)); - return GNUNET_SYSERR; - } - /* Fake HTTP client request with #input_filename as input. - We do this using the nc tool. */ - GNUNET_snprintf (ports, - sizeof (ports), - "%u", - serve_port); - if (0 == (cld = fork())) - { - GNUNET_break (0 == close (0)); - GNUNET_break (0 == dup2 (fd, 0)); - GNUNET_break (0 == close (fd)); - if ( (0 != execlp ("nc", - "nc", - "localhost", - ports, - "-w", "30", - NULL)) && - (0 != execlp ("ncat", - "ncat", - "localhost", - ports, - "-i", "30", - NULL)) ) - { - fprintf (stderr, - "Failed to run both `nc' and `ncat': %s\n", - strerror (errno)); - } - _exit (1); - } - /* parent process */ - GNUNET_break (0 == close (fd)); - ret = TMH_KS_loop (); - if (cld != waitpid (cld, &status, 0)) - fprintf (stderr, - "Waiting for `nc' child failed: %s\n", - strerror (errno)); - return ret; -} - - -/** - * Signature of the callback used by MHD to notify the application - * about completed connections. If we are running in test-mode with - * an #input_filename, this function is used to terminate the HTTPD - * after the first request has been processed. - * - * @param cls client-defined closure, NULL - * @param connection connection handle (ignored) - * @param socket_context socket-specific pointer (ignored) - * @param toe reason for connection notification - */ -static void -connection_done (void *cls, - struct MHD_Connection *connection, - void **socket_context, - enum MHD_ConnectionNotificationCode toe) -{ - /* We only act if the connection is closed. */ - if (MHD_CONNECTION_NOTIFY_CLOSED != toe) - return; - /* This callback is also present if the option wasn't, so - make sure the option was actually set. */ - if (NULL == input_filename) - return; - /* We signal ourselves to terminate. */ - if (0 != kill (getpid(), - SIGTERM)) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "kill"); -} - -/* end of HAVE_DEVELOPER */ -#endif - - -/** - * Function called for logging by MHD. - * - * @param cls closure, NULL - * @param fm format string (`printf()`-style) - * @param ap arguments to @a fm - */ -static void -handle_mhd_logs (void *cls, - const char *fm, - va_list ap) -{ - char buf[2048]; - - vsnprintf (buf, - sizeof (buf), - fm, - ap); - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "libmicrohttpd", - "%s", - buf); -} - - -/** - * The main function of the taler-mint-httpd server ("the mint"). - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'C', "connection-close", NULL, - "force HTTP connections to be closed after each request", 0, - &GNUNET_GETOPT_set_one, &TMH_mint_connection_close}, - {'d', "mint-dir", "DIR", - "mint directory with configuration and keys for operating the mint", 1, - &GNUNET_GETOPT_set_filename, &TMH_mint_directory}, - {'t', "timeout", "SECONDS", - "after how long do connections timeout by default (in seconds)", 1, - &GNUNET_GETOPT_set_uint, &connection_timeout}, -#if HAVE_DEVELOPER - {'f', "file-input", "FILENAME", - "run in test-mode using FILENAME as the HTTP request to process", 1, - &GNUNET_GETOPT_set_filename, &input_filename}, -#endif - TALER_GETOPT_OPTION_HELP ("HTTP server providing a RESTful API to access a Taler mint"), - GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), - GNUNET_GETOPT_OPTION_END - }; - int ret; - - GNUNET_assert (GNUNET_OK == - GNUNET_log_setup ("taler-mint-httpd", - "INFO", - NULL)); - if (0 >= - GNUNET_GETOPT_run ("taler-mint-httpd", - options, - argc, argv)) - return 1; - if (NULL == TMH_mint_directory) - { - fprintf (stderr, - "Mint directory not specified\n"); - return 1; - } - - if (GNUNET_OK != - mint_serve_process_config (TMH_mint_directory)) - return 1; - - mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, - serve_port, - NULL, NULL, - &handle_mhd_request, NULL, - MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL, - MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL, - MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout, -#if HAVE_DEVELOPER - MHD_OPTION_NOTIFY_CONNECTION, &connection_done, NULL, -#endif - MHD_OPTION_END); - - if (NULL == mydaemon) - { - fprintf (stderr, - "Failed to start HTTP server.\n"); - return 1; - } -#if HAVE_DEVELOPER - if (NULL != input_filename) - { - /* run only the testfile input, then terminate */ - ret = run_fake_client (); - } - else - { - /* normal behavior */ - ret = TMH_KS_loop (); - } -#else - /* normal behavior */ - ret = TMH_KS_loop (); -#endif - - switch (ret) - { - case GNUNET_OK: - case GNUNET_SYSERR: - MHD_stop_daemon (mydaemon); - break; - case GNUNET_NO: - { - MHD_socket sock = MHD_quiesce_daemon (mydaemon); - - /* FIXME #3474: fork another MHD, passing on the listen socket! */ - while (0 != MHD_get_daemon_info (mydaemon, - MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->num_connections) - sleep (1); - MHD_stop_daemon (mydaemon); - - close (sock); /* FIXME: done like this because #3474 is open */ - } - break; - default: - GNUNET_break (0); - MHD_stop_daemon (mydaemon); - break; - } - - if (GNUNET_YES == TMH_test_mode) - { - struct TALER_MINTDB_Session *session; - - session = TMH_plugin->get_session (TMH_plugin->cls, - GNUNET_YES); - if (NULL == session) - GNUNET_break (0); - else - TMH_plugin->drop_temporary (TMH_plugin->cls, - session); - } - TALER_MINTDB_plugin_unload (TMH_plugin); - TMH_VALIDATION_done (); - return (GNUNET_SYSERR == ret) ? 1 : 0; -} - -/* end of taler-mint-httpd.c */ diff --git a/src/mint/taler-mint-httpd.h b/src/mint/taler-mint-httpd.h deleted file mode 100644 index d45325aa6..000000000 --- a/src/mint/taler-mint-httpd.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd.h - * @brief Global declarations for the mint - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - * - * FIXME: Consider which of these need to really be globals... - */ -#ifndef TALER_MINT_HTTPD_H -#define TALER_MINT_HTTPD_H - -#include <microhttpd.h> - - -/** - * Which currency is used by this mint? - */ -extern char *TMH_mint_currency_string; - -/** - * Should we return "Connection: close" in each response? - */ -extern int TMH_mint_connection_close; - -/** - * The mint's configuration. - */ -extern struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Are we running in test mode? - */ -extern int TMH_test_mode; - -/** - * Main directory with mint data. - */ -extern char *TMH_mint_directory; - -/** - * Master public key (according to the - * configuration in the mint directory). - */ -extern struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key; - -/** - * Private key of the mint we use to sign messages. - */ -extern struct GNUNET_CRYPTO_EddsaPrivateKey TMH_mint_private_signing_key; - -/** - * Our DB plugin. - */ -extern struct TALER_MINTDB_Plugin *TMH_plugin; - - -/** - * @brief Struct describing an URL and the handler for it. - */ -struct TMH_RequestHandler -{ - - /** - * URL the handler is for. - */ - const char *url; - - /** - * Method the handler is for, NULL for "all". - */ - const char *method; - - /** - * Mime type to use in reply (hint, can be NULL). - */ - const char *mime_type; - - /** - * Raw data for the @e handler - */ - const void *data; - - /** - * Number of bytes in @e data, 0 for 0-terminated. - */ - size_t data_size; - - /** - * Function to call to handle the request. - * - * @param rh this struct - * @param mime_type the @e mime_type for the reply (hint, can be NULL) - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ - int (*handler)(struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - /** - * Default response code. - */ - int response_code; -}; - - -#endif diff --git a/src/mint/taler-mint-httpd_admin.c b/src/mint/taler-mint-httpd_admin.c deleted file mode 100644 index e6f186f0b..000000000 --- a/src/mint/taler-mint-httpd_admin.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_admin.c - * @brief Handle /admin/ requests - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler-mint-httpd_admin.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_validation.h" - - -/** - * Check permissions (we only allow access to /admin/ from loopback). - * - * @param connection connection to perform access check for - * @return #GNUNET_OK if permitted, - * #GNUNET_NO if denied and error was queued, - * #GNUNET_SYSERR if denied and we failed to report - */ -static int -check_permissions (struct MHD_Connection *connection) -{ - const union MHD_ConnectionInfo *ci; - const struct sockaddr *addr; - int res; - - ci = MHD_get_connection_info (connection, - MHD_CONNECTION_INFO_CLIENT_ADDRESS); - if (NULL == ci) - { - GNUNET_break (0); - res = TMH_RESPONSE_reply_internal_error (connection, - "Failed to verify client address"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - addr = ci->client_addr; - switch (addr->sa_family) - { - case AF_INET: - { - const struct sockaddr_in *sin = (const struct sockaddr_in *) addr; - - if (INADDR_LOOPBACK != ntohl (sin->sin_addr.s_addr)) - { - res = TMH_RESPONSE_reply_permission_denied (connection, - "/admin/ only allowed via loopback"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - break; - } - case AF_INET6: - { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr; - - if (! IN6_IS_ADDR_LOOPBACK (&sin6->sin6_addr)) - { - res = TMH_RESPONSE_reply_permission_denied (connection, - "/admin/ only allowed via loopback"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - break; - } - default: - GNUNET_break (0); - res = TMH_RESPONSE_reply_internal_error (connection, - "Unsupported AF"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - return GNUNET_OK; -} - - - -/** - * Handle a "/admin/add/incoming" request. Parses the - * given "reserve_pub", "amount", "transaction" and "h_wire" - * details and adds the respective transaction to the database. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_Amount amount; - struct GNUNET_TIME_Absolute at; - json_t *wire; - json_t *root; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub), - TMH_PARSE_member_amount ("amount", &amount), - TMH_PARSE_member_time_abs ("execution_date", &at), - TMH_PARSE_member_object ("wire", &wire), - TMH_PARSE_MEMBER_END - }; - int res; - - res = check_permissions (connection); - if (GNUNET_OK != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - json_decref (root); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - if (GNUNET_YES != - TMH_json_validate_wireformat (wire)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "wire"); - } - res = TMH_DB_execute_admin_add_incoming (connection, - &reserve_pub, - &amount, - at, - wire); - TMH_PARSE_release_data (spec); - return res; -} - -/* end of taler-mint-httpd_admin.c */ diff --git a/src/mint/taler-mint-httpd_admin.h b/src/mint/taler-mint-httpd_admin.h deleted file mode 100644 index b8ca3ce59..000000000 --- a/src/mint/taler-mint-httpd_admin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_admin.h - * @brief Handle /admin/ requests - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_ADMIN_H -#define TALER_MINT_HTTPD_ADMIN_H - -#include <microhttpd.h> -#include "taler-mint-httpd.h" - -/** - * Handle a "/admin/add/incoming" request. Parses the - * given "reserve_pub", "amount", "transaction" and "h_wire" - * details and adds the respective transaction to the database. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c deleted file mode 100644 index 8c22a0a2a..000000000 --- a/src/mint/taler-mint-httpd_db.c +++ /dev/null @@ -1,1900 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_db.c - * @brief High-level (transactional-layer) database operations for the mint. - * @author Christian Grothoff - */ -#include "platform.h" -#include <pthread.h> -#include <jansson.h> -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - -/** - * How often should we retry a transaction before giving up - * (for transactions resulting in serialization/dead locks only). - */ -#define MAX_TRANSACTION_COMMIT_RETRIES 3 - -/** - * Code to begin a transaction, must be inline as we define a block - * that ends with #COMMIT_TRANSACTION() within which we perform a number - * of retries. Note that this code may call "return" internally, so - * it must be called within a function where any cleanup will be done - * by the caller. Furthermore, the function's return value must - * match that of a #TMH_RESPONSE_reply_internal_db_error() status code. - * - * @param session session handle - * @param connection connection handle - */ -#define START_TRANSACTION(session,connection) \ -{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\ - unsigned int transaction_retries = 0; \ - int transaction_commit_result; \ -transaction_start_label: /* we will use goto for retries */ \ - if (GNUNET_OK != \ - TMH_plugin->start (TMH_plugin->cls, \ - session)) \ - { \ - GNUNET_break (0); \ - return TMH_RESPONSE_reply_internal_db_error (connection); \ - } - -/** - * Code to conclude a transaction, dual to #START_TRANSACTION(). Note - * that this code may call "return" internally, so it must be called - * within a function where any cleanup will be done by the caller. - * Furthermore, the function's return value must match that of a - * #TMH_RESPONSE_reply_internal_db_error() status code. - * - * @param session session handle - * @param connection connection handle - */ -#define COMMIT_TRANSACTION(session,connection) \ - transaction_commit_result = \ - TMH_plugin->commit (TMH_plugin->cls, \ - session); \ - if (GNUNET_SYSERR == transaction_commit_result) \ - { \ - TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ - return TMH_RESPONSE_reply_commit_error (connection); \ - } \ - if (GNUNET_NO == transaction_commit_result) \ - { \ - TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ - if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \ - goto transaction_start_label; \ - TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \ - transaction_retries, \ - __FUNCTION__); \ - return TMH_RESPONSE_reply_commit_error (connection); \ - } \ -} /* end of scope opened by BEGIN_TRANSACTION */ - - -/** - * Calculate the total value of all transactions performed. - * Stores @a off plus the cost of all transactions in @a tl - * in @a ret. - * - * @param tl transaction list to process - * @param off offset to use as the starting value - * @param ret where the resulting total is to be stored - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static int -calculate_transaction_list_totals (struct TALER_MINTDB_TransactionList *tl, - const struct TALER_Amount *off, - struct TALER_Amount *ret) -{ - struct TALER_Amount spent = *off; - struct TALER_MINTDB_TransactionList *pos; - - for (pos = tl; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_TT_DEPOSIT: - if (GNUNET_OK != - TALER_amount_add (&spent, - &spent, - &pos->details.deposit->amount_with_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - break; - case TALER_MINTDB_TT_REFRESH_MELT: - if (GNUNET_OK != - TALER_amount_add (&spent, - &spent, - &pos->details.melt->amount_with_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - break; - } - } - *ret = spent; - return GNUNET_OK; -} - - -/** - * Execute a deposit. The validity of the coin and signature - * have already been checked. The database must now check that - * the coin is not (double or over) spent, and execute the - * transaction (record details, generate success or failure response). - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -int -TMH_DB_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit) -{ - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_TransactionList *tl; - struct TALER_Amount spent; - struct TALER_Amount value; - struct TALER_Amount amount_without_fee; - struct TMH_KS_StateHandle *mks; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - int ret; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_YES == - TMH_plugin->have_deposit (TMH_plugin->cls, - session, - deposit)) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&amount_without_fee, - &deposit->amount_with_fee, - &deposit->deposit_fee)); - return TMH_RESPONSE_reply_deposit_success (connection, - &deposit->coin.coin_pub, - &deposit->h_wire, - &deposit->h_contract, - deposit->transaction_id, - deposit->timestamp, - deposit->refund_deadline, - &deposit->merchant_pub, - &amount_without_fee); - } - mks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (mks, - &deposit->coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (mks); - return TMH_RESPONSE_reply_arg_invalid (connection, - "denom_pub"); - } - TALER_amount_ntoh (&value, - &dki->issue.properties.value); - TMH_KS_release (mks); - - START_TRANSACTION (session, connection); - - /* fee for THIS transaction */ - spent = deposit->amount_with_fee; - /* add cost of all previous transactions */ - tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, - session, - &deposit->coin.coin_pub); - if (GNUNET_OK != - calculate_transaction_list_totals (tl, - &spent, - &spent)) - { - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - /* Check that cost of all transactions is smaller than - the value of the coin. */ - if (0 < TALER_amount_cmp (&spent, - &value)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - ret = TMH_RESPONSE_reply_deposit_insufficient_funds (connection, - tl); - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return ret; - } - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - - if (GNUNET_OK != - TMH_plugin->insert_deposit (TMH_plugin->cls, - session, - deposit)) - { - TALER_LOG_WARNING ("Failed to store /deposit information in database\n"); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - COMMIT_TRANSACTION(session, connection); - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&amount_without_fee, - &deposit->amount_with_fee, - &deposit->deposit_fee)); - return TMH_RESPONSE_reply_deposit_success (connection, - &deposit->coin.coin_pub, - &deposit->h_wire, - &deposit->h_contract, - deposit->transaction_id, - deposit->timestamp, - deposit->refund_deadline, - &deposit->merchant_pub, - &amount_without_fee); -} - - -/** - * Execute a /reserve/status. Given the public key of a reserve, - * return the associated transaction history. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve to check - * @return MHD result code - */ -int -TMH_DB_execute_reserve_status (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_ReserveHistory *rh; - int res; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, - session, - reserve_pub); - if (NULL == rh) - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:s}", - "error", "Reserve not found", - "parameter", "withdraw_pub"); - res = TMH_RESPONSE_reply_reserve_status_success (connection, - rh); - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - return res; -} - - -/** - * Try to execute /reserve/withdraw transaction. - * - * @param connection request we are handling - * @param session database session we are using - * @param key_state key state to lookup denomination pubs - * @param reserve reserve to withdraw from - * @param denomination_pub public key of the denomination requested - * @param dki denomination to withdraw - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param h_blind hash of @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @param denom_sig[out] where to write the resulting signature - * (used to release memory in case of transaction failure - * @return MHD result code - */ -static int -execute_reserve_withdraw_transaction (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - struct TMH_KS_StateHandle *key_state, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki, - const char *blinded_msg, - size_t blinded_msg_len, - const struct GNUNET_HashCode *h_blind, - const struct TALER_ReserveSignatureP *signature, - struct TALER_DenominationSignature *denom_sig) -{ - struct TALER_MINTDB_ReserveHistory *rh; - const struct TALER_MINTDB_ReserveHistory *pos; - struct TALER_MINTDB_DenominationKeyIssueInformation *tdki; - struct TALER_MINTDB_CollectableBlindcoin collectable; - struct TALER_Amount amount_required; - struct TALER_Amount deposit_total; - struct TALER_Amount withdraw_total; - struct TALER_Amount balance; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - int res; - - /* Check if balance is sufficient */ - START_TRANSACTION (session, connection); - rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, - session, - reserve); - if (NULL == rh) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_arg_unknown (connection, - "reserve_pub"); - } - - /* calculate amount required including fees */ - TALER_amount_ntoh (&value, - &dki->issue.properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - - if (GNUNET_OK != - TALER_amount_add (&amount_required, - &value, - &fee_withdraw)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* calculate balance of the reserve */ - res = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - if (0 == (res & 1)) - deposit_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.bank->amount)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res |= 1; - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - tdki = TMH_KS_denomination_key_lookup (key_state, - &pos->details.withdraw->denom_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == tdki) - { - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - TALER_amount_ntoh (&value, - &tdki->issue.properties.value); - if (0 == (res & 2)) - withdraw_total = value; - else - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &value)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res |= 2; - break; - } - } - if (0 == (res & 1)) - { - /* did not encounter any deposit operations, how can we have a reserve? */ - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (0 == (res & 2)) - { - /* did not encounter any withdraw operations, set to zero */ - TALER_amount_get_zero (deposit_total.currency, - &withdraw_total); - } - /* All reserve balances should be non-negative */ - GNUNET_assert (GNUNET_SYSERR != - TALER_amount_subtract (&balance, - &deposit_total, - &withdraw_total)); - if (0 < TALER_amount_cmp (&amount_required, - &balance)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - res = TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (connection, - rh); - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - return res; - } - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - - /* Balance is good, sign the coin! */ - denom_sig->rsa_signature - = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, - blinded_msg, - blinded_msg_len); - if (NULL == denom_sig->rsa_signature) - { - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_error (connection, - "Internal error"); - } - collectable.sig = *denom_sig; - collectable.denom_pub = *denomination_pub; - collectable.amount_with_fee = amount_required; - collectable.withdraw_fee = fee_withdraw; - collectable.reserve_pub = *reserve; - collectable.h_coin_envelope = *h_blind; - collectable.reserve_sig = *signature; - if (GNUNET_OK != - TMH_plugin->insert_withdraw_info (TMH_plugin->cls, - session, - &collectable)) - { - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - COMMIT_TRANSACTION (session, connection); - - return TMH_RESPONSE_reply_reserve_withdraw_success (connection, - &collectable); -} - - - -/** - * Execute a "/reserve/withdraw". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature) -{ - struct TALER_MINTDB_Session *session; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_MINTDB_CollectableBlindcoin collectable; - struct TALER_DenominationSignature denom_sig; - struct GNUNET_HashCode h_blind; - int res; - - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &h_blind); - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, - session, - &h_blind, - &collectable); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* Don't sign again if we have already signed the coin */ - if (GNUNET_YES == res) - { - res = TMH_RESPONSE_reply_reserve_withdraw_success (connection, - &collectable); - GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); - return res; - } - GNUNET_assert (GNUNET_NO == res); - - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - denomination_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - "Denomination not found"); - } - denom_sig.rsa_signature = NULL; - res = execute_reserve_withdraw_transaction (connection, - session, - key_state, - reserve, - denomination_pub, - dki, - blinded_msg, - blinded_msg_len, - &h_blind, - signature, - &denom_sig); - if (NULL != denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature); - TMH_KS_release (key_state); - return res; -} - - -/** - * Parse coin melt requests from a JSON object and write them to - * the database. - * - * @param connection the connection to send errors to - * @param session the database connection - * @param key_state the mint's key state - * @param session_hash hash identifying the refresh session - * @param coin_details details about the coin being melted - * @param oldcoin_index what is the number assigned to this coin - * @return #GNUNET_OK on success, - * #GNUNET_NO if an error message was generated, - * #GNUNET_SYSERR on internal errors (no response generated) - */ -static int -refresh_accept_melts (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct TMH_KS_StateHandle *key_state, - const struct GNUNET_HashCode *session_hash, - const struct TMH_DB_MeltDetails *coin_details, - uint16_t oldcoin_index) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dk; - struct TALER_MINTDB_DenominationKeyInformationP *dki; - struct TALER_MINTDB_TransactionList *tl; - struct TALER_Amount coin_value; - struct TALER_Amount coin_residual; - struct TALER_Amount spent; - struct TALER_MINTDB_RefreshMelt melt; - int res; - - dk = TMH_KS_denomination_key_lookup (key_state, - &coin_details->coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dk) - return (MHD_YES == - TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub")) - ? GNUNET_NO : GNUNET_SYSERR; - dki = &dk->issue; - TALER_amount_ntoh (&coin_value, - &dki->properties.value); - /* fee for THIS transaction; the melt amount includes the fee! */ - spent = coin_details->melt_amount_with_fee; - /* add historic transaction costs of this coin */ - tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, - session, - &coin_details->coin_info.coin_pub); - if (GNUNET_OK != - calculate_transaction_list_totals (tl, - &spent, - &spent)) - { - GNUNET_break (0); - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return (MHD_YES == - TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - /* Refuse to refresh when the coin's value is insufficient - for the cost of all transactions. */ - if (TALER_amount_cmp (&coin_value, - &spent) < 0) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&coin_residual, - &spent, - &coin_details->melt_amount_with_fee)); - res = (MHD_YES == - TMH_RESPONSE_reply_refresh_melt_insufficient_funds (connection, - &coin_details->coin_info.coin_pub, - coin_value, - tl, - coin_details->melt_amount_with_fee, - coin_residual)) - ? GNUNET_NO : GNUNET_SYSERR; - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return res; - } - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - - melt.coin = coin_details->coin_info; - melt.coin_sig = coin_details->melt_sig; - melt.session_hash = *session_hash; - melt.amount_with_fee = coin_details->melt_amount_with_fee; - melt.melt_fee = coin_details->melt_fee; - if (GNUNET_OK != - TMH_plugin->insert_refresh_melt (TMH_plugin->cls, - session, - oldcoin_index, - &melt)) - { - GNUNET_break (0); - return (MHD_YES == - TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Execute a "/refresh/melt". We have been given a list of valid - * coins and a request to melt them into the given - * @a refresh_session_pub. Check that the coins all have the - * required value left and if so, store that they have been - * melted and confirm the melting operation to the client. - * - * @param connection the MHD connection to handle - * @param session_hash hash code of the session the coins are melted into - * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array - * @param denom_pubs public keys of the coins we want to withdraw in the end - * @param coin_count number of entries in @a coin_melt_details, size of y-dimension of @a commit_link array - * @param coin_melt_details signatures and (residual) value of the respective coin should be melted - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done), - * x-dimension must be #TALER_CNC_KAPPA - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * x-dimension must be #TALER_CNC_KAPPA - * @return MHD result code - */ -int -TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_RefreshCommitLinkP *const* commit_link) -{ - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_RefreshSession refresh_session; - struct TALER_MINTDB_Session *session; - int res; - unsigned int i; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - START_TRANSACTION (session, connection); - res = TMH_plugin->get_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session); - if (GNUNET_YES == res) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - res = TMH_RESPONSE_reply_refresh_melt_success (connection, - session_hash, - refresh_session.noreveal_index); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - if (GNUNET_SYSERR == res) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* store 'global' session data */ - refresh_session.num_oldcoins = coin_count; - refresh_session.num_newcoins = num_new_denoms; - refresh_session.noreveal_index - = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - TALER_CNC_KAPPA); - if (GNUNET_OK != - (res = TMH_plugin->create_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session))) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* Melt old coins and check that they had enough residual value */ - key_state = TMH_KS_acquire (); - for (i=0;i<coin_count;i++) - { - if (GNUNET_OK != - (res = refresh_accept_melts (connection, - session, - key_state, - session_hash, - &coin_melt_details[i], - i))) - { - TMH_KS_release (key_state); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - } - TMH_KS_release (key_state); - - /* store requested new denominations */ - if (GNUNET_OK != - TMH_plugin->insert_refresh_order (TMH_plugin->cls, - session, - session_hash, - num_new_denoms, - denom_pubs)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - if (GNUNET_OK != - TMH_plugin->insert_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - i, - num_new_denoms, - commit_coin[i])) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - if (GNUNET_OK != - TMH_plugin->insert_refresh_commit_links (TMH_plugin->cls, - session, - session_hash, - i, - coin_count, - commit_link[i])) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - - COMMIT_TRANSACTION (session, connection); - return TMH_RESPONSE_reply_refresh_melt_success (connection, - session_hash, - refresh_session.noreveal_index); -} - - -/** - * Send an error response with the details of the original melt - * commitment and the location of the mismatch. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param off commitment offset to check - * @param index index of the mismatch - * @param object_name name of the object with the problem - * @return #GNUNET_NO if we generated the error message - * #GNUNET_SYSERR if we could not even generate an error message - */ -static int -send_melt_commitment_error (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - unsigned int off, - unsigned int index, - const char *object_name) -{ - struct TALER_MINTDB_MeltCommitment *mc; - int ret; - - mc = TMH_plugin->get_melt_commitment (TMH_plugin->cls, - session, - session_hash); - if (NULL == mc) - { - GNUNET_break (0); - return (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "Melt commitment assembly")) - ? GNUNET_NO : GNUNET_SYSERR; - } - ret = (MHD_YES == - TMH_RESPONSE_reply_refresh_reveal_missmatch (connection, - mc, - off, - index, - object_name)) - ? GNUNET_NO : GNUNET_SYSERR; - TMH_plugin->free_melt_commitment (TMH_plugin->cls, - mc); - return ret; -} - - -/** - * Check if the given @a transfer_privs correspond to an honest - * commitment for the given session. - * Checks that the transfer private keys match their commitments. - * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param off commitment offset to check - * @param num_oldcoins size of the @a transfer_privs and @a melts arrays - * @param transfer_privs private transfer keys - * @param melts array of melted coins - * @param num_newcoins number of newcoins being generated - * @param denom_pubs array of @a num_newcoins keys for the new coins - * @return #GNUNET_OK if the committment was honest, - * #GNUNET_NO if there was a problem and we generated an error message - * #GNUNET_SYSERR if we could not even generate an error message - */ -static int -check_commitment (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - unsigned int off, - unsigned int num_oldcoins, - const struct TALER_TransferPrivateKeyP *transfer_privs, - const struct TALER_MINTDB_RefreshMelt *melts, - unsigned int num_newcoins, - const struct TALER_DenominationPublicKey *denom_pubs) -{ - unsigned int j; - struct TALER_LinkSecretP last_shared_secret; - int secret_initialized = GNUNET_NO; - struct TALER_RefreshCommitLinkP *commit_links; - struct TALER_MINTDB_RefreshCommitCoin *commit_coins; - - commit_links = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_RefreshCommitLinkP)); - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_links (TMH_plugin->cls, - session, - session_hash, - off, - num_oldcoins, - commit_links)) - { - GNUNET_break (0); - GNUNET_free (commit_links); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - for (j = 0; j < num_oldcoins; j++) - { - struct TALER_LinkSecretP shared_secret; - struct TALER_TransferPublicKeyP transfer_pub_check; - - GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[j].ecdhe_priv, - &transfer_pub_check.ecdhe_pub); - if (0 != - memcmp (&transfer_pub_check, - &commit_links[j].transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "transfer keys do not match\n"); - GNUNET_free (commit_links); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "transfer key"); - } - - if (GNUNET_OK != - TALER_link_decrypt_secret (&commit_links[j].shared_secret_enc, - &transfer_privs[j], - &melts[j].coin.coin_pub, - &shared_secret)) - { - GNUNET_free (commit_links); - return (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "Transfer secret decryption error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (GNUNET_NO == secret_initialized) - { - secret_initialized = GNUNET_YES; - last_shared_secret = shared_secret; - } - else if (0 != memcmp (&shared_secret, - &last_shared_secret, - sizeof (struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "shared secrets do not match\n"); - GNUNET_free (commit_links); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "transfer secret"); - } - } - GNUNET_break (GNUNET_YES == secret_initialized); - GNUNET_free (commit_links); - - /* Check that the commitments for all new coins were correct */ - commit_coins = GNUNET_malloc (num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - off, - num_newcoins, - commit_coins)) - { - GNUNET_break (0); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - for (j = 0; j < num_newcoins; j++) - { - struct TALER_RefreshLinkDecrypted *link_data; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode h_msg; - char *buf; - size_t buf_len; - - link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link, - &last_shared_secret); - if (NULL == link_data) - { - GNUNET_break (0); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, - "Decryption error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&link_data->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP), - &h_msg); - if (0 == (buf_len = - GNUNET_CRYPTO_rsa_blind (&h_msg, - link_data->blinding_key.rsa_blinding_key, - denom_pubs[j].rsa_public_key, - &buf))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "blind failed\n"); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, - "Blinding error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - if ( (buf_len != commit_coins[j].coin_ev_size) || - (0 != memcmp (buf, - commit_coins[j].coin_ev, - buf_len)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "blind envelope does not match for k=%u, old=%d\n", - off, - (int) j); - GNUNET_free (commit_coins); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "envelope"); - } - GNUNET_free (buf); - } - GNUNET_free (commit_coins); - - return GNUNET_OK; -} - - -/** - * Mint a coin as part of a refresh operation. Obtains the - * envelope from the database and performs the signing operation. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param key_state key state to lookup denomination pubs - * @param denom_pub denomination key for the coin to create - * @param commit_coin the coin that was committed - * @param coin_off number of the coin - * @return NULL on error, otherwise signature over the coin - */ -static struct TALER_DenominationSignature -refresh_mint_coin (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_MINTDB_RefreshCommitCoin *commit_coin, - unsigned int coin_off) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_DenominationSignature ev_sig; - - dki = TMH_KS_denomination_key_lookup (key_state, - denom_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - GNUNET_break (0); - ev_sig.rsa_signature = NULL; - return ev_sig; - } - ev_sig.rsa_signature - = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, - commit_coin->coin_ev, - commit_coin->coin_ev_size); - if (NULL == ev_sig.rsa_signature) - { - GNUNET_break (0); - return ev_sig; - } - if (GNUNET_OK != - TMH_plugin->insert_refresh_out (TMH_plugin->cls, - session, - session_hash, - coin_off, - &ev_sig)) - { - GNUNET_break (0); - GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature); - ev_sig.rsa_signature = NULL; - } - return ev_sig; -} - - -/** - * The client request was well-formed, now execute the DB transaction - * of a "/refresh/reveal" operation. We use the @a ev_sigs and - * @a commit_coins to clean up resources after this function returns - * as we might experience retries of the database transaction. - * - * @param connection the MHD connection to handle - * @param session database session - * @param session_hash hash identifying the refresh session - * @param refresh_session information about the refresh operation we are doing - * @param melts array of "num_oldcoins" with information about melted coins - * @param denom_pubs array of "num_newcoins" denomination keys for the new coins - * @param[out] ev_sigs where to store generated signatures for the new coins, - * array of length "num_newcoins", memory released by the - * caller - * @param[out] commit_coins array of length "num_newcoins" to be used for - * information about the new coins from the commitment. - * @return MHD result code - */ -static int -execute_refresh_reveal_transaction (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - const struct TALER_MINTDB_RefreshSession *refresh_session, - const struct TALER_MINTDB_RefreshMelt *melts, - const struct TALER_DenominationPublicKey *denom_pubs, - struct TALER_DenominationSignature *ev_sigs, - struct TALER_MINTDB_RefreshCommitCoin *commit_coins) -{ - unsigned int j; - struct TMH_KS_StateHandle *key_state; - - START_TRANSACTION (session, connection); - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - refresh_session->noreveal_index, - refresh_session->num_newcoins, - commit_coins)) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - key_state = TMH_KS_acquire (); - for (j=0;j<refresh_session->num_newcoins;j++) - { - if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */ - ev_sigs[j] = refresh_mint_coin (connection, - session, - session_hash, - key_state, - &denom_pubs[j], - &commit_coins[j], - j); - if (NULL == ev_sigs[j].rsa_signature) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - TMH_KS_release (key_state); - COMMIT_TRANSACTION (session, connection); - return TMH_RESPONSE_reply_refresh_reveal_success (connection, - refresh_session->num_newcoins, - ev_sigs); -} - - -/** - * Execute a "/refresh/reveal". The client is revealing to us the - * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the - * revealed transfer keys would allow linkage to the blinded coins, - * and if so, return the signed coins for corresponding to the set of - * coins that was not chosen. - * - * @param connection the MHD connection to handle - * @param session_hash hash identifying the refresh session - * @param num_oldcoins size of y-dimension of @a transfer_privs array - * @param transfer_privs array with the revealed transfer keys, - * x-dimension must be #TALER_CNC_KAPPA - 1 - * @return MHD result code - */ -int -TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - struct TALER_TransferPrivateKeyP **transfer_privs) -{ - int res; - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_RefreshSession refresh_session; - struct TALER_MINTDB_RefreshMelt *melts; - struct TALER_DenominationPublicKey *denom_pubs; - struct TALER_DenominationSignature *ev_sigs; - struct TALER_MINTDB_RefreshCommitCoin *commit_coins; - unsigned int i; - unsigned int j; - unsigned int off; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - res = TMH_plugin->get_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session); - if (GNUNET_NO == res) - return TMH_RESPONSE_reply_arg_invalid (connection, - "session_hash"); - if (GNUNET_SYSERR == res) - return TMH_RESPONSE_reply_internal_db_error (connection); - if (0 == refresh_session.num_oldcoins) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - melts = GNUNET_malloc (refresh_session.num_oldcoins * - sizeof (struct TALER_MINTDB_RefreshMelt)); - for (j=0;j<refresh_session.num_oldcoins;j++) - { - if (GNUNET_OK != - TMH_plugin->get_refresh_melt (TMH_plugin->cls, - session, - session_hash, - j, - &melts[j])) - { - GNUNET_break (0); - for (i=0;i<j;i++) - { - GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); - } - GNUNET_free (melts); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - denom_pubs = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_DenominationPublicKey)); - if (GNUNET_OK != - TMH_plugin->get_refresh_order (TMH_plugin->cls, - session, - session_hash, - refresh_session.num_newcoins, - denom_pubs)) - { - GNUNET_break (0); - GNUNET_free (denom_pubs); - for (i=0;i<refresh_session.num_oldcoins;i++) - { - GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); - } - GNUNET_free (melts); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - - off = 0; - for (i=0;i<TALER_CNC_KAPPA - 1;i++) - { - if (i == refresh_session.noreveal_index) - off = 1; - if (GNUNET_OK != - (res = check_commitment (connection, - session, - session_hash, - i + off, - refresh_session.num_oldcoins, - transfer_privs[i], - melts, - refresh_session.num_newcoins, - denom_pubs))) - { - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - for (i=0;i<refresh_session.num_oldcoins;i++) - { - GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); - } - GNUNET_free (melts); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - } - for (i=0;i<refresh_session.num_oldcoins;i++) - { - GNUNET_CRYPTO_rsa_signature_free (melts[i].coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (melts[i].coin.denom_pub.rsa_public_key); - } - GNUNET_free (melts); - - /* Client request OK, start transaction */ - commit_coins = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - ev_sigs = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_DenominationSignature)); - res = execute_refresh_reveal_transaction (connection, - session, - session_hash, - &refresh_session, - melts, - denom_pubs, - ev_sigs, - commit_coins); - for (i=0;i<refresh_session.num_newcoins;i++) - if (NULL != ev_sigs[i].rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); - for (j=0;j<refresh_session.num_newcoins;j++) - if (NULL != denom_pubs[j].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (ev_sigs); - GNUNET_free (denom_pubs); - GNUNET_free (commit_coins); - return res; -} - - -/** - * Closure for #handle_transfer_data(). - */ -struct HTD_Context -{ - - /** - * Session link data we collect. - */ - struct TMH_RESPONSE_LinkSessionInfo *sessions; - - /** - * Database session. Nothing to do with @a sessions. - */ - struct TALER_MINTDB_Session *session; - - /** - * MHD connection, for queueing replies. - */ - struct MHD_Connection *connection; - - /** - * Number of sessions the coin was melted into. - */ - unsigned int num_sessions; - - /** - * How are we expected to proceed. #GNUNET_SYSERR if we - * failed to return an error (should return #MHD_NO). - * #GNUNET_NO if we succeeded in queueing an MHD error - * (should return #MHD_YES from #TMH_execute_refresh_link), - * #GNUNET_OK if we should call #TMH_RESPONSE_reply_refresh_link_success(). - */ - int status; -}; - - -/** - * Function called with the session hashes and transfer secret - * information for a given coin. Gets the linkage data and - * builds the reply for the client. - * - * - * @param cls closure, a `struct HTD_Context` - * @param session_hash a session the coin was melted in - * @param transfer_pub public transfer key for the session - * @param shared_secret_enc set to shared secret for the session - */ -static void -handle_transfer_data (void *cls, - const struct GNUNET_HashCode *session_hash, - const struct TALER_TransferPublicKeyP *transfer_pub, - const struct TALER_EncryptedLinkSecretP *shared_secret_enc) -{ - struct HTD_Context *ctx = cls; - struct TALER_MINTDB_LinkDataList *ldl; - struct TMH_RESPONSE_LinkSessionInfo *lsi; - - if (GNUNET_OK != ctx->status) - return; - ldl = TMH_plugin->get_link_data_list (TMH_plugin->cls, - ctx->session, - session_hash); - if (NULL == ldl) - { - ctx->status = GNUNET_NO; - if (MHD_NO == - TMH_RESPONSE_reply_json_pack (ctx->connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - "link data not found (link)")) - ctx->status = GNUNET_SYSERR; - return; - } - GNUNET_array_grow (ctx->sessions, - ctx->num_sessions, - ctx->num_sessions + 1); - lsi = &ctx->sessions[ctx->num_sessions - 1]; - lsi->transfer_pub = *transfer_pub; - lsi->shared_secret_enc = *shared_secret_enc; - lsi->ldl = ldl; -} - - -/** - * Execute a "/refresh/link". Returns the linkage information that - * will allow the owner of a coin to follow the refresh trail to - * the refreshed coin. - * - * @param connection the MHD connection to handle - * @param coin_pub public key of the coin to link - * @return MHD result code - */ -int -TMH_DB_execute_refresh_link (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub) -{ - struct HTD_Context ctx; - int res; - unsigned int i; - - if (NULL == (ctx.session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ctx.connection = connection; - ctx.num_sessions = 0; - ctx.sessions = NULL; - ctx.status = GNUNET_OK; - res = TMH_plugin->get_transfer (TMH_plugin->cls, - ctx.session, - coin_pub, - &handle_transfer_data, - &ctx); - if (GNUNET_SYSERR == ctx.status) - { - res = MHD_NO; - goto cleanup; - } - if (GNUNET_NO == ctx.status) - { - res = MHD_YES; - goto cleanup; - } - GNUNET_assert (GNUNET_OK == ctx.status); - if (0 == ctx.num_sessions) - return TMH_RESPONSE_reply_arg_unknown (connection, - "coin_pub"); - res = TMH_RESPONSE_reply_refresh_link_success (connection, - ctx.num_sessions, - ctx.sessions); - cleanup: - for (i=0;i<ctx.num_sessions;i++) - TMH_plugin->free_link_data_list (TMH_plugin->cls, - ctx.sessions[i].ldl); - GNUNET_free_non_null (ctx.sessions); - return res; -} - - -/** - * Add an incoming transaction to the database. Checks if the - * transaction is fresh (not a duplicate) and if so adds it to - * the database. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve - * @param amount amount to add to the reserve - * @param execution_time when did we receive the wire transfer - * @param wire details about the wire transfer - * @return MHD result code - */ -int -TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_time, - json_t *wire) -{ - struct TALER_MINTDB_Session *session; - int ret; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ret = TMH_plugin->reserves_in_insert (TMH_plugin->cls, - session, - reserve_pub, - amount, - execution_time, - wire); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s}", - "status", - (GNUNET_OK == ret) - ? "NEW" - : "DUP"); -} - - -/** - * Closure for #handle_transaction_data. - */ -struct WtidTransactionContext -{ - - /** - * Total amount of the wire transfer, as calculated by - * summing up the individual amounts. To be rounded down - * to calculate the real transfer amount at the end. - * Only valid if @e is_valid is #GNUNET_YES. - */ - struct TALER_Amount total; - - /** - * Public key of the merchant, only valid if @e is_valid - * is #GNUNET_YES. - */ - struct TALER_MerchantPublicKeyP merchant_pub; - - /** - * Hash of the wire details of the merchant (identical for all - * deposits), only valid if @e is_valid is #GNUNET_YES. - */ - struct GNUNET_HashCode h_wire; - - /** - * JSON array with details about the individual deposits. - */ - json_t *deposits; - - /** - * Initially #GNUNET_NO, if we found no deposits so far. Set to - * #GNUNET_YES if we got transaction data, and the database replies - * remained consistent with respect to @e merchant_pub and @e h_wire - * (as they should). Set to #GNUNET_SYSERR if we encountered an - * internal error. - */ - int is_valid; - -}; - - -/** - * Function called with the results of the lookup of the - * transaction data for the given wire transfer identifier. - * - * @param cls our context for transmission - * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param h_contract which contract was this payment about - * @param transaction_id merchant's transaction ID for the payment - * @param coin_pub which public key was this payment about - * @param deposit_value amount contributed by this coin in total - * @param deposit_fee deposit fee charged by mint for this coin - */ -static void -handle_transaction_data (void *cls, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *deposit_value, - const struct TALER_Amount *deposit_fee) -{ - struct WtidTransactionContext *ctx = cls; - struct TALER_Amount delta; - - if (GNUNET_SYSERR == ctx->is_valid) - return; - if (GNUNET_NO == ctx->is_valid) - { - ctx->merchant_pub = *merchant_pub; - ctx->h_wire = *h_wire; - ctx->is_valid = GNUNET_YES; - if (GNUNET_OK != - TALER_amount_subtract (&ctx->total, - deposit_value, - deposit_fee)) - { - GNUNET_break (0); - ctx->is_valid = GNUNET_SYSERR; - return; - } - } - else - { - if ( (0 != memcmp (&ctx->merchant_pub, - merchant_pub, - sizeof (struct TALER_MerchantPublicKeyP))) || - (0 != memcmp (&ctx->h_wire, - h_wire, - sizeof (struct GNUNET_HashCode))) ) - { - GNUNET_break (0); - ctx->is_valid = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - TALER_amount_subtract (&delta, - deposit_value, - deposit_fee)) - { - GNUNET_break (0); - ctx->is_valid = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - TALER_amount_add (&ctx->total, - &ctx->total, - &delta)) - { - GNUNET_break (0); - ctx->is_valid = GNUNET_SYSERR; - return; - } - } - /* NOTE: We usually keep JSON stuff out of the _DB file, and this - is also ugly if we ever add signatures over this data. (#4135) */ - json_array_append (ctx->deposits, - json_pack ("{s:o, s:o, s:o, s:I, s:o}", - "deposit_value", TALER_json_from_amount (deposit_value), - "deposit_fee", TALER_json_from_amount (deposit_fee), - "H_contract", TALER_json_from_data (h_contract, - sizeof (struct GNUNET_HashCode)), - "transaction_id", (json_int_t) transaction_id, - "coin_pub", TALER_json_from_data (coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)))); -} - - -/** - * Execute a "/wire/deposits". Returns the transaction information - * associated with the given wire transfer identifier. - * - * @param connection the MHD connection to handle - * @param wtid wire transfer identifier to resolve - * @return MHD result code - */ -int -TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, - const struct TALER_WireTransferIdentifierRawP *wtid) -{ - int ret; - struct WtidTransactionContext ctx; - struct TALER_MINTDB_Session *session; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ctx.is_valid = GNUNET_NO; - ctx.deposits = json_array (); - ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls, - session, - wtid, - &handle_transaction_data, - &ctx); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - json_decref (ctx.deposits); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_SYSERR == ctx.is_valid) - { - GNUNET_break (0); - json_decref (ctx.deposits); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_NO == ctx.is_valid) - { - json_decref (ctx.deposits); - return TMH_RESPONSE_reply_arg_unknown (connection, - "wtid"); - } - return TMH_RESPONSE_reply_wire_deposit_details (connection, - &ctx.total, - &ctx.merchant_pub, - &ctx.h_wire, - ctx.deposits); -} - - -/** - * Closure for #handle_wtid_data. - */ -struct DepositWtidContext -{ - - /** - * Where should we send the reply? - */ - struct MHD_Connection *connection; - - /** - * Hash of the contract we are looking up. - */ - struct GNUNET_HashCode h_contract; - - /** - * Hash of the wire transfer details we are looking up. - */ - struct GNUNET_HashCode h_wire; - - /** - * Public key we are looking up. - */ - struct TALER_CoinSpendPublicKeyP coin_pub; - - /** - * Transaction ID we are looking up. - */ - uint64_t transaction_id; - - /** - * MHD result code to return. - */ - int res; -}; - - -/** - * Function called with the results of the lookup of the - * wire transfer identifier information. - * - * @param cls our context for transmission - * @param wtid raw wire transfer identifier, NULL - * if the transaction was not yet done - * @param coin_contribution how much did the coin we asked about - * contribute to the total transfer value? (deposit value including fee) - * @param coin_fee how much did the mint charge for the deposit fee - * @param execution_time when was the transaction done, or - * when we expect it to be done (if @a wtid was NULL); - * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown - * to the mint - */ -static void -handle_wtid_data (void *cls, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_Amount *coin_contribution, - const struct TALER_Amount *coin_fee, - struct GNUNET_TIME_Absolute execution_time) -{ - struct DepositWtidContext *ctx = cls; - struct TALER_Amount coin_delta; - - if (NULL == wtid) - { - ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection, - execution_time); - } - else - { - if (GNUNET_SYSERR == - TALER_amount_subtract (&coin_delta, - coin_contribution, - coin_fee)) - { - GNUNET_break (0); - ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection); - } - else - { - ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection, - &ctx->h_contract, - &ctx->h_wire, - &ctx->coin_pub, - &coin_delta, - ctx->transaction_id, - wtid, - execution_time); - } - } -} - - -/** - * Execute a "/deposit/wtid". Returns the transfer information - * associated with the given deposit. - * - * @param connection the MHD connection to handle - * @param h_contract hash of the contract - * @param h_wire hash of the wire details - * @param coin_pub public key of the coin to link - * @param merchant_pub public key of the merchant - * @param transaction_id transaction ID of the merchant - * @return MHD result code - */ -int -TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_MerchantPublicKeyP *merchant_pub, - uint64_t transaction_id) -{ - int ret; - struct DepositWtidContext ctx; - struct TALER_MINTDB_Session *session; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ctx.connection = connection; - ctx.h_contract = *h_contract; - ctx.h_wire = *h_wire; - ctx.coin_pub = *coin_pub; - ctx.transaction_id = transaction_id; - ctx.res = GNUNET_SYSERR; - ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls, - session, - h_contract, - h_wire, - coin_pub, - merchant_pub, - transaction_id, - &handle_wtid_data, - &ctx); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - GNUNET_break (GNUNET_SYSERR == ctx.res); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_NO == ret) - { - GNUNET_break (GNUNET_SYSERR == ctx.res); - return TMH_RESPONSE_reply_deposit_unknown (connection); - } - if (GNUNET_SYSERR == ctx.res) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_error (connection, - "bug resolving deposit wtid"); - } - return ctx.res; -} - - -/* end of taler-mint-httpd_db.c */ diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h deleted file mode 100644 index 0327bef2a..000000000 --- a/src/mint/taler-mint-httpd_db.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/taler-mint-httpd_db.h - * @brief High-level (transactional-layer) database operations for the mint - * @author Chrisitan Grothoff - */ -#ifndef TALER_MINT_HTTPD_DB_H -#define TALER_MINT_HTTPD_DB_H - -#include <microhttpd.h> -#include "taler_mintdb_plugin.h" - - -/** - * Execute a "/deposit". The validity of the coin and signature - * have already been checked. The database must now check that - * the coin is not (double or over) spent, and execute the - * transaction (record details, generate success or failure response). - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -int -TMH_DB_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit); - - -/** - * Execute a "/reserve/status". Given the public key of a reserve, - * return the associated transaction history. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve to check - * @return MHD result code - */ -int -TMH_DB_execute_reserve_status (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub); - - -/** - * Execute a "/reserve/withdraw". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TMH_DB_execute_reserve_withdraw (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature); - - -/** - * @brief Details about a melt operation of an individual coin. - */ -struct TMH_DB_MeltDetails -{ - - /** - * Information about the coin being melted. - */ - struct TALER_CoinPublicInfo coin_info; - - /** - * Signature allowing the melt (using - * a `struct TALER_MINTDB_RefreshMeltConfirmSignRequestBody`) to sign over. - */ - struct TALER_CoinSpendSignatureP melt_sig; - - /** - * How much of the coin's value did the client allow to be melted? - * This amount includes the fees, so the final amount contributed - * to the melt is this value minus the fee for melting the coin. - */ - struct TALER_Amount melt_amount_with_fee; - - /** - * What fee is earned by the mint? Set delayed during - * #verify_coin_public_info(). - */ - struct TALER_Amount melt_fee; -}; - - -/** - * Execute a "/refresh/melt". We have been given a list of valid - * coins and a request to melt them into the given - * @a refresh_session_pub. Check that the coins all have the - * required value left and if so, store that they have been - * melted and confirm the melting operation to the client. - * - * @param connection the MHD connection to handle - * @param session_hash hash code of the session the coins are melted into - * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array - * @param denom_pubs array of public denomination keys for the refresh (?) - * @param coin_count number of entries in @ a coin_melt_details, size of y-dimension of @a commit_link array - * @param coin_melt_details signatures and (residual) value of and information about the respective coin to be melted - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done) - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * @return MHD result code - */ -int -TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_RefreshCommitLinkP *const* commit_link); - - -/** - * Execute a "/refresh/reveal". The client is revealing to us the - * transfer keys for #TALER_CNC_KAPPA-1 sets of coins. Verify that the - * revealed transfer keys would allow linkage to the blinded coins, - * and if so, return the signed coins for corresponding to the set of - * coins that was not chosen. - * - * @param connection the MHD connection to handle - * @param session_hash hash over the refresh session - * @param num_oldcoins size of y-dimension of @a transfer_privs array - * @param transfer_privs array with the revealed transfer keys, #TALER_CNC_KAPPA is 1st-dimension - * @return MHD result code - */ -int -TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - struct TALER_TransferPrivateKeyP **transfer_privs); - - -/** - * Execute a "/refresh/link". Returns the linkage information that - * will allow the owner of a coin to follow the refresh trail to the - * refreshed coin. - * - * @param connection the MHD connection to handle - * @param coin_pub public key of the coin to link - * @return MHD result code - */ -int -TMH_DB_execute_refresh_link (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub); - - - -/** - * Add an incoming transaction to the database. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve - * @param amount amount to add to the reserve - * @param execution_time when did we receive the wire transfer - * @param wire details about the wire transfer - * @return MHD result code - */ -int -TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_time, - json_t *wire); - - -/** - * Execute a "/wire/deposits". Returns the transaction information - * associated with the given wire transfer identifier. - * - * @param connection the MHD connection to handle - * @param wtid wire transfer identifier to resolve - * @return MHD result code - */ -int -TMH_DB_execute_wire_deposits (struct MHD_Connection *connection, - const struct TALER_WireTransferIdentifierRawP *wtid); - - -/** - * Execute a "/deposit/wtid". Returns the transfer information - * associated with the given deposit. - * - * @param connection the MHD connection to handle - * @param h_contract hash of the contract - * @param h_wire hash of the wire details - * @param coin_pub public key of the coin to link - * @param merchant_pub public key of the merchant - * @param transaction_id transaction ID of the merchant - * @return MHD result code - */ -int -TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_MerchantPublicKeyP *merchant_pub, - uint64_t transaction_id); - - -#endif -/* TALER_MINT_HTTPD_DB_H */ diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c deleted file mode 100644 index 40c5a4db7..000000000 --- a/src/mint/taler-mint-httpd_deposit.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_deposit.c - * @brief Handle /deposit requests; parses the POST and JSON and - * verifies the coin signature before handing things off - * to the database. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - * - * TODO: - * - ugly if-construction for deposit type - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_deposit.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" -#include "taler-mint-httpd_validation.h" - - -/** - * We have parsed the JSON information about the deposit, do some - * basic sanity checks (especially that the signature on the coin is - * valid, and that this type of coin exists) and then execute the - * deposit. - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -static int -verify_and_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit) -{ - struct TMH_KS_StateHandle *key_state; - struct TALER_DepositRequestPS dr; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_Amount fee_deposit; - - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = deposit->h_contract; - dr.h_wire = deposit->h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); - dr.transaction_id = GNUNET_htonll (deposit->transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - &deposit->amount_with_fee); - TALER_amount_hton (&dr.deposit_fee, - &deposit->deposit_fee); - dr.merchant = deposit->merchant_pub; - dr.coin_pub = deposit->coin.coin_pub; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &deposit->csig.eddsa_signature, - &deposit->coin.coin_pub.eddsa_pub)) - { - TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); - return TMH_RESPONSE_reply_signature_invalid (connection, - "coin_sig"); - } - /* check denomination exists and is valid */ - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - &deposit->coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (key_state); - TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - /* check coin signature */ - if (GNUNET_YES != - TALER_test_coin_valid (&deposit->coin)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_signature_invalid (connection, - "ub_sig"); - } - TALER_amount_ntoh (&fee_deposit, - &dki->issue.properties.fee_deposit); - if (0 < TALER_amount_cmp (&fee_deposit, - &deposit->amount_with_fee)) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_external_error (connection, - "deposited amount smaller than depositing fee"); - } - TMH_KS_release (key_state); - - return TMH_DB_execute_deposit (connection, - deposit); -} - - -/** - * Handle a "/deposit" request. This function parses the - * JSON information and then calls #verify_and_execute_deposit() - * to verify the signatures and execute the deposit. - * - * @param connection the MHD connection to handle - * @param root root of the posted JSON - * @param amount how much should be deposited - * @param wire json describing the wire details (?) - * @return MHD result code - */ -static int -parse_and_handle_deposit_request (struct MHD_Connection *connection, - const json_t *root, - const struct TALER_Amount *amount, - json_t *wire) -{ - int res; - struct TALER_MINTDB_Deposit deposit; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TMH_KS_StateHandle *ks; - struct GNUNET_HashCode my_h_wire; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub), - TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig), - TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub), - TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub), - TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract), - TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire), - TMH_PARSE_member_fixed ("coin_sig", &deposit.csig), - TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id), - TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp), - TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline), - TMH_PARSE_member_time_abs ("edate", &deposit.wire_deadline), - TMH_PARSE_MEMBER_END - }; - - memset (&deposit, 0, sizeof (deposit)); - res = TMH_PARSE_json_data (connection, - root, - spec); - if (GNUNET_SYSERR == res) - return MHD_NO; /* hard failure */ - if (GNUNET_NO == res) - return MHD_YES; /* failure */ - - if (GNUNET_YES != - TMH_json_validate_wireformat (wire)) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "wire"); - } - if (GNUNET_OK != - TALER_hash_json (wire, - &my_h_wire)) - { - TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n"); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "wire"); - } - if (0 != memcmp (&deposit.h_wire, - &my_h_wire, - sizeof (struct GNUNET_HashCode))) - { - /* Client hashed contract differently than we did, reject */ - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "H_wire"); - } - ks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (ks, - &deposit.coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (ks); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - TALER_amount_ntoh (&deposit.deposit_fee, - &dki->issue.properties.fee_deposit); - TMH_KS_release (ks); - deposit.wire = wire; - deposit.amount_with_fee = *amount; - if (-1 == TALER_amount_cmp (&deposit.amount_with_fee, - &deposit.deposit_fee)) - { - /* Total amount smaller than fee, invalid */ - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "f"); - } - res = verify_and_execute_deposit (connection, - &deposit); - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/deposit" request. Parses the JSON in the post to find - * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if - * successful, passes the JSON data to - * #parse_and_handle_deposit_request() to further check the details - * of the operation specified in the "wire" field of the JSON data. - * If everything checks out, this will ultimately lead to the - * "/deposit" being executed, or rejected. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - json_t *wire; - int res; - struct TALER_Amount amount; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_object ("wire", &wire), - TMH_PARSE_member_amount ("f", &amount), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - if (GNUNET_OK != res) - { - json_decref (json); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - res = parse_and_handle_deposit_request (connection, - json, - &amount, - wire); - TMH_PARSE_release_data (spec); - json_decref (json); - return res; -} - - -/* end of taler-mint-httpd_deposit.c */ diff --git a/src/mint/taler-mint-httpd_deposit.h b/src/mint/taler-mint-httpd_deposit.h deleted file mode 100644 index c2d3fe13c..000000000 --- a/src/mint/taler-mint-httpd_deposit.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_deposit.h - * @brief Handle /deposit requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_DEPOSIT_H -#define TALER_MINT_HTTPD_DEPOSIT_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/deposit" request. Parses the JSON in the post to find - * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if - * successful, passes the JSON data to - * #parse_and_handle_deposit_request() to further check the details - * of the operation specified in the "wire" field of the JSON data. - * If everything checks out, this will ultimately lead to the - * "/deposit" being executed, or rejected. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/mint/taler-mint-httpd_keystate.c b/src/mint/taler-mint-httpd_keystate.c deleted file mode 100644 index f1856e673..000000000 --- a/src/mint/taler-mint-httpd_keystate.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_keystate.c - * @brief management of our coin signing keys - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <pthread.h> -#include "taler-mint-httpd_keystate.h" -#include "taler-mint-httpd_responses.h" -#include "taler_mintdb_plugin.h" - - -/** - * Snapshot of the (coin and signing) keys (including private keys) of - * the mint. There can be multiple instances of this struct, as it is - * reference counted and only destroyed once the last user is done - * with it. The current instance is acquired using - * #TMH_KS_acquire(). Using this function increases the - * reference count. The contents of this structure (except for the - * reference counter) should be considered READ-ONLY until it is - * ultimately destroyed (as there can be many concurrent users). - */ -struct TMH_KS_StateHandle -{ - /** - * JSON array with denomination keys. (Currently not really used - * after initialization.) - */ - json_t *denom_keys_array; - - /** - * JSON array with signing keys. (Currently not really used - * after initialization.) - */ - json_t *sign_keys_array; - - /** - * JSON array with auditor information. (Currently not really used - * after initialization.) - */ - json_t *auditors_array; - - /** - * Cached JSON text that the mint will send for a "/keys" request. - * Includes our @e TMH_master_public_key public key, the signing and - * denomination keys as well as the @e reload_time. - */ - char *keys_json; - - /** - * Mapping from denomination keys to denomination key issue struct. - * Used to lookup the key by hash. - */ - struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; - - /** - * Hash context we used to combine the hashes of all denomination - * keys into one big hash. - */ - struct GNUNET_HashContext *hash_context; - - /** - * When did we initiate the key reloading? - */ - struct GNUNET_TIME_Absolute reload_time; - - /** - * When is the next key invalid and we have to reload? (We also - * reload on SIGUSR1.) - */ - struct GNUNET_TIME_Absolute next_reload; - - /** - * Mint signing key that should be used currently. - */ - struct TALER_MINTDB_PrivateSigningKeyInformationP current_sign_key_issue; - - /** - * Reference count. The struct is released when the RC hits zero. - */ - unsigned int refcnt; -}; - - -/** - * Mint key state. Never use directly, instead access via - * #TMH_KS_acquire() and #TMH_KS_release(). - */ -static struct TMH_KS_StateHandle *internal_key_state; - -/** - * Mutex protecting access to #internal_key_state. - */ -static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * Pipe used for signaling reloading of our key state. - */ -static int reload_pipe[2]; - - -/** - * Convert the public part of a denomination key issue to a JSON - * object. - * - * @param pk public key of the denomination key - * @param dki the denomination key issue - * @return a JSON object describing the denomination key isue (public part) - */ -static json_t * -denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk, - const struct TALER_MINTDB_DenominationKeyInformationP *dki) -{ - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_deposit; - struct TALER_Amount fee_refresh; - - TALER_amount_ntoh (&value, - &dki->properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->properties.fee_withdraw); - TALER_amount_ntoh (&fee_deposit, - &dki->properties.fee_deposit); - TALER_amount_ntoh (&fee_refresh, - &dki->properties.fee_refresh); - return - json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", - "master_sig", - TALER_json_from_data (&dki->signature, - sizeof (struct GNUNET_CRYPTO_EddsaSignature)), - "stamp_start", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)), - "stamp_expire_withdraw", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)), - "stamp_expire_deposit", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)), - "stamp_expire_legal", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)), - "denom_pub", - TALER_json_from_rsa_public_key (pk->rsa_public_key), - "value", - TALER_json_from_amount (&value), - "fee_withdraw", - TALER_json_from_amount (&fee_withdraw), - "fee_deposit", - TALER_json_from_amount (&fee_deposit), - "fee_refresh", - TALER_json_from_amount (&fee_refresh)); -} - - -/** - * Get the relative time value that describes how - * far in the future do we want to provide coin keys. - * - * @return the provide duration - */ -static struct GNUNET_TIME_Relative -TALER_MINT_conf_duration_provide () -{ - struct GNUNET_TIME_Relative rel; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, - "mint_keys", - "lookahead_provide", - &rel)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "mint_keys", - "lookahead_provide", - "time value required"); - GNUNET_assert (0); - } - return rel; -} - - -/** - * Iterator for (re)loading/initializing denomination keys. - * - * @param cls closure - * @param dki the denomination key issue - * @param alias coin alias - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -reload_keys_denom_iter (void *cls, - const char *alias, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - struct TMH_KS_StateHandle *ctx = cls; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute horizon; - struct GNUNET_HashCode denom_key_hash; - struct TALER_MINTDB_DenominationKeyIssueInformation *d2; - struct TALER_MINTDB_Session *session; - int res; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Loading denomination key `%s'\n", - alias); - horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ()); - if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us > - horizon.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping future denomination key `%s'\n", - alias); - return GNUNET_OK; - } - now = GNUNET_TIME_absolute_get (); - if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us < - now.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping expired denomination key `%s'\n", - alias); - return GNUNET_OK; - } - - GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key, - &denom_key_hash); - GNUNET_CRYPTO_hash_context_read (ctx->hash_context, - &denom_key_hash, - sizeof (struct GNUNET_HashCode)); - session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode); - if (NULL == session) - return GNUNET_SYSERR; - /* Try to insert DKI into DB until we succeed; note that if the DB - failure is persistent, this code may loop forever (as there is no - sane alternative, we cannot continue without the DKI being in the - DB). */ - res = GNUNET_SYSERR; - while (GNUNET_OK != res) - { - res = TMH_plugin->start (TMH_plugin->cls, - session); - if (GNUNET_OK != res) - { - /* Transaction start failed!? Very bad error, log and retry */ - GNUNET_break (0); - continue; - } - res = TMH_plugin->get_denomination_info (TMH_plugin->cls, - session, - &dki->denom_pub, - NULL); - if (GNUNET_SYSERR == res) - { - /* Fetch failed!? Very bad error, log and retry */ - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - continue; - } - if (GNUNET_OK == res) - { - /* Record exists, we're good, just exit */ - TMH_plugin->rollback (TMH_plugin->cls, - session); - break; - } - res = TMH_plugin->insert_denomination_info (TMH_plugin->cls, - session, - &dki->denom_pub, - &dki->issue); - if (GNUNET_OK != res) - { - /* Insert failed!? Very bad error, log and retry */ - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - continue; - } - res = TMH_plugin->commit (TMH_plugin->cls, - session); - /* If commit succeeded, we're done, otherwise we retry; this - time without logging, as theroetically commits can fail - in a transactional DB due to concurrent activities that - cannot be reconciled. This should be rare for DKIs, but - as it is possible we just retry until we succeed. */ - } - - d2 = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation); - d2->issue = dki->issue; - d2->denom_priv.rsa_private_key - = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key); - d2->denom_pub.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); - res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map, - &denom_key_hash, - d2, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - if (GNUNET_OK != res) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Duplicate denomination key `%s'\n", - alias); - GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key); - GNUNET_free (d2); - return GNUNET_OK; - } - json_array_append_new (ctx->denom_keys_array, - denom_key_issue_to_json (&dki->denom_pub, - &dki->issue)); - return GNUNET_OK; -} - - -/** - * Convert the public part of a sign key issue to a JSON object. - * - * @param ski the sign key issue - * @return a JSON object describing the sign key issue (public part) - */ -static json_t * -sign_key_issue_to_json (const struct TALER_MintSigningKeyValidityPS *ski) -{ - return - json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", - "stamp_start", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)), - "stamp_expire", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)), - "stamp_end", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->end)), - "master_pub", - TALER_json_from_data (&ski->master_public_key, - sizeof (struct TALER_MasterPublicKeyP)), - "master_sig", - TALER_json_from_data (&ski->signature, - sizeof (struct TALER_MasterSignatureP)), - "key", - TALER_json_from_data (&ski->signkey_pub, - sizeof (struct TALER_MintPublicKeyP))); -} - - -/** - * Iterator for sign keys. - * - * @param cls closure with the `struct TMH_KS_StateHandle *` - * @param filename name of the file the key came from - * @param ski the sign key issue - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -reload_keys_sign_iter (void *cls, - const char *filename, - const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski) -{ - struct TMH_KS_StateHandle *ctx = cls; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute horizon; - - horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ()); - if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us > - horizon.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping future signing key `%s'\n", - filename); - return GNUNET_OK; - } - now = GNUNET_TIME_absolute_get (); - if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us < - now.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping expired signing key `%s'\n", - filename); - return GNUNET_OK; - } - - /* The signkey is valid at this time, check if it's more recent than - what we have so far! */ - if ( (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us < - GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) && - (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us < - now.abs_value_us) ) - { - /* We use the most recent one, if it is valid now (not just in the near future) */ - ctx->current_sign_key_issue = *ski; - } - json_array_append_new (ctx->sign_keys_array, - sign_key_issue_to_json (&ski->issue)); - - return GNUNET_OK; -} - - -/** - * Convert information from an auditor to a JSON object. - * - * @param apub the auditor's public key - * @param dki_len length of @a dki and @a asigs arrays - * @param asigs the auditor's signatures - * @param dki array of denomination coin data signed by the auditor - * @return a JSON object describing the auditor information and signature - */ -static json_t * -auditor_to_json (const struct TALER_AuditorPublicKeyP *apub, - unsigned int dki_len, - const struct TALER_AuditorSignatureP **asigs, - const struct TALER_DenominationKeyValidityPS **dki) -{ - unsigned int i; - json_t *ja; - - ja = json_array (); - for (i=0;i<dki_len;i++) - json_array_append_new (ja, - json_pack ("{s:o, s:o}", - "denom_pub_h", - TALER_json_from_data (&dki[i]->denom_hash, - sizeof (struct GNUNET_HashCode)), - "auditor_sig", - TALER_json_from_data (asigs[i], - sizeof (struct TALER_AuditorSignatureP)))); - return - json_pack ("{s:o, s:o}", - "denomination_keys", ja, - "auditor_pub", - TALER_json_from_data (apub, - sizeof (struct TALER_AuditorPublicKeyP))); -} - - -/** - * @brief Iterator called with auditor information. - * Check that the @a mpub actually matches this mint, and then - * add the auditor information to our /keys response (if it is - * (still) applicable). - * - * @param cls closure with the `struct TMH_KS_StateHandle *` - * @param apub the auditor's public key - * @param mpub the mint's public key (as expected by the auditor) - * @param dki_len length of @a dki and @a asigs - * @param asigs array with the auditor's signatures, of length @a dki_len - * @param dki array of denomination coin data signed by the auditor - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -reload_auditor_iter (void *cls, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_DenominationKeyValidityPS *dki) -{ - struct TMH_KS_StateHandle *ctx = cls; - unsigned int i; - unsigned int keep; - const struct TALER_AuditorSignatureP *kept_asigs[dki_len]; - const struct TALER_DenominationKeyValidityPS *kept_dkis[dki_len]; - - /* Check if the signature is at least for this mint. */ - if (0 != memcmp (&mpub->eddsa_pub, - &TMH_master_public_key, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Auditing information provided for a different mint, ignored\n"); - return GNUNET_OK; - } - /* Filter the auditor information for those for which the - keys actually match the denomination keys that are active right now */ - keep = 0; - for (i=0;i<dki_len;i++) - { - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (ctx->denomkey_map, - &dki[i].denom_hash)) - { - kept_asigs[keep] = &asigs[i]; - kept_dkis[keep] = &dki[i]; - keep++; - } - } - /* add auditor information to our /keys response */ - json_array_append_new (ctx->auditors_array, - auditor_to_json (apub, - keep, - kept_asigs, - kept_dkis)); - return GNUNET_OK; -} - - -/** - * Iterator for freeing denomination keys. - * - * @param cls closure with the `struct TMH_KS_StateHandle` - * @param key key for the denomination key - * @param value coin details - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -free_denom_key (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki = value; - - GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key); - GNUNET_free (dki); - return GNUNET_OK; -} - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * Internal method used when the mutex is already held. - * - * @param key_state the key state to release - */ -static void -ks_release_ (struct TMH_KS_StateHandle *key_state) -{ - GNUNET_assert (0 < key_state->refcnt); - key_state->refcnt--; - if (0 == key_state->refcnt) - { - if (NULL != key_state->denom_keys_array) - { - json_decref (key_state->denom_keys_array); - key_state->denom_keys_array = NULL; - } - if (NULL != key_state->sign_keys_array) - { - json_decref (key_state->sign_keys_array); - key_state->sign_keys_array = NULL; - } - if (NULL != key_state->denomkey_map) - { - GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map, - &free_denom_key, - key_state); - GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map); - key_state->denomkey_map = NULL; - } - GNUNET_free_non_null (key_state->keys_json); - GNUNET_free (key_state); - } -} - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * - * @param location name of the function in which the lock is acquired - * @param key_state the key state to release - */ -void -TMH_KS_release_ (const char *location, - struct TMH_KS_StateHandle *key_state) -{ - GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); - ks_release_ (key_state); - GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); -} - - -/** - * Acquire the key state of the mint. Updates keys if necessary. - * For every call to #TMH_KS_acquire(), a matching call - * to #TMH_KS_release() must be made. - * - * @param location name of the function in which the lock is acquired - * @return the key state - */ -struct TMH_KS_StateHandle * -TMH_KS_acquire_ (const char *location) -{ - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct TMH_KS_StateHandle *key_state; - json_t *keys; - struct TALER_MintKeySetPS ks; - struct TALER_MintSignatureP sig; - - GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); - if ( (NULL != internal_key_state) && - (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) ) - { - ks_release_ (internal_key_state); - internal_key_state = NULL; - } - if (NULL == internal_key_state) - { - key_state = GNUNET_new (struct TMH_KS_StateHandle); - key_state->hash_context = GNUNET_CRYPTO_hash_context_start (); - - - key_state->denom_keys_array = json_array (); - GNUNET_assert (NULL != key_state->denom_keys_array); - - key_state->sign_keys_array = json_array (); - GNUNET_assert (NULL != key_state->sign_keys_array); - - key_state->auditors_array = json_array (); - GNUNET_assert (NULL != key_state->auditors_array); - - key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32, - GNUNET_NO); - key_state->reload_time = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (&key_state->reload_time); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Loading keys from `%s'\n", - TMH_mint_directory); - TALER_MINTDB_denomination_keys_iterate (TMH_mint_directory, - &reload_keys_denom_iter, - key_state); - TALER_MINTDB_signing_keys_iterate (TMH_mint_directory, - &reload_keys_sign_iter, - key_state); - TALER_MINTDB_auditor_iterate (TMH_mint_directory, - &reload_auditor_iter, - key_state); - ks.purpose.size = htonl (sizeof (ks)); - ks.purpose.purpose = htonl (TALER_SIGNATURE_MINT_KEY_SET); - ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time); - GNUNET_CRYPTO_hash_context_finish (key_state->hash_context, - &ks.hc); - key_state->hash_context = NULL; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, - &ks.purpose, - &sig.eddsa_signature)); - key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire); - if (0 == key_state->next_reload.abs_value_us) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No valid signing key found!\n"); - - keys = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o}", - "master_public_key", - TALER_json_from_data (&TMH_master_public_key, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)), - "signkeys", key_state->sign_keys_array, - "denoms", key_state->denom_keys_array, - "auditors", key_state->auditors_array, - "list_issue_date", TALER_json_from_abs (key_state->reload_time), - "eddsa_pub", TALER_json_from_data (&key_state->current_sign_key_issue.issue.signkey_pub, - sizeof (struct TALER_MintPublicKeyP)), - "eddsa_sig", TALER_json_from_data (&sig, - sizeof (struct TALER_MintSignatureP))); - key_state->auditors_array = NULL; - key_state->sign_keys_array = NULL; - key_state->denom_keys_array = NULL; - key_state->keys_json = json_dumps (keys, - JSON_INDENT (2)); - json_decref (keys); - internal_key_state = key_state; - } - key_state = internal_key_state; - key_state->refcnt++; - GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); - - return key_state; -} - - -/** - * Look up the issue for a denom public key. - * - * @param key_state state to look in - * @param denom_pub denomination public key - * @param use purpose for which the key is being located - * @return the denomination key issue, - * or NULL if denom_pub could not be found - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - enum TMH_KS_DenominationKeyUse use) -{ - struct GNUNET_HashCode hc; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct GNUNET_TIME_Absolute now; - - GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key, - &hc); - dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map, - &hc); - if (NULL == dki) - return NULL; - now = GNUNET_TIME_absolute_get (); - if (now.abs_value_us < - GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as start time is in the future\n", - GNUNET_h2s (&hc)); - return NULL; - } - now = GNUNET_TIME_absolute_get (); - switch (use) - { - case TMH_KS_DKU_WITHDRAW: - if (now.abs_value_us > - GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as time to create coins has passed\n", - GNUNET_h2s (&hc)); - return NULL; - } - break; - case TMH_KS_DKU_DEPOSIT: - if (now.abs_value_us > - GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as time to spend coin has passed\n", - GNUNET_h2s (&hc)); - return NULL; - } - break; - } - return dki; -} - - -/** - * Handle a signal, writing relevant signal numbers to the pipe. - * - * @param signal_number the signal number - */ -static void -handle_signal (int signal_number) -{ - ssize_t res; - char c = signal_number; - - res = write (reload_pipe[1], - &c, - 1); - if ( (res < 0) && - (EINTR != errno) ) - { - GNUNET_break (0); - return; - } - if (0 == res) - { - GNUNET_break (0); - return; - } -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigusr1 () -{ - handle_signal (SIGUSR1); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigint () -{ - handle_signal (SIGINT); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigterm () -{ - handle_signal (SIGTERM); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sighup () -{ - handle_signal (SIGHUP); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigchld () -{ - handle_signal (SIGCHLD); -} - - -/** - * Read signals from a pipe in a loop, and reload keys from disk if - * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and - * restart if SIGHUP is received. - * - * @return #GNUNET_SYSERR on errors, - * #GNUNET_OK to terminate normally - * #GNUNET_NO to restart an update version of the binary - */ -int -TMH_KS_loop (void) -{ - struct GNUNET_SIGNAL_Context *sigusr1; - struct GNUNET_SIGNAL_Context *sigterm; - struct GNUNET_SIGNAL_Context *sigint; - struct GNUNET_SIGNAL_Context *sighup; - struct GNUNET_SIGNAL_Context *sigchld; - int ret; - - if (0 != pipe (reload_pipe)) - { - fprintf (stderr, - "Failed to create pipe.\n"); - return GNUNET_SYSERR; - } - sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1, - &handle_sigusr1); - sigterm = GNUNET_SIGNAL_handler_install (SIGTERM, - &handle_sigterm); - sigint = GNUNET_SIGNAL_handler_install (SIGINT, - &handle_sigint); - sighup = GNUNET_SIGNAL_handler_install (SIGHUP, - &handle_sighup); - sigchld = GNUNET_SIGNAL_handler_install (SIGCHLD, - &handle_sigchld); - - ret = 0; - while (0 == ret) - { - char c; - ssize_t res; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "(re-)loading keys\n"); - if (NULL != internal_key_state) - { - TMH_KS_release (internal_key_state); - internal_key_state = NULL; - } - /* This will re-initialize 'internal_key_state' with - an initial refcnt of 1 */ - (void) TMH_KS_acquire (); - -read_again: - errno = 0; - res = read (reload_pipe[0], - &c, - 1); - if ((res < 0) && (EINTR != errno)) - { - GNUNET_break (0); - ret = GNUNET_SYSERR; - break; - } - if (EINTR == errno) - goto read_again; - switch (c) - { - case SIGUSR1: - /* reload internal key state, we do this in the loop */ - break; - case SIGTERM: - case SIGINT: - /* terminate */ - ret = GNUNET_OK; - break; - case SIGHUP: - /* restart updated binary */ - ret = GNUNET_NO; - break; -#if HAVE_DEVELOPER - case SIGCHLD: - /* running in test-mode, test finished, terminate */ - ret = GNUNET_OK; - break; -#endif - default: - /* unexpected character */ - GNUNET_break (0); - break; - } - } - if (NULL != internal_key_state) - { - TMH_KS_release (internal_key_state); - internal_key_state = NULL; - } - GNUNET_SIGNAL_handler_uninstall (sigusr1); - GNUNET_SIGNAL_handler_uninstall (sigterm); - GNUNET_SIGNAL_handler_uninstall (sigint); - GNUNET_SIGNAL_handler_uninstall (sighup); - GNUNET_SIGNAL_handler_uninstall (sigchld); - return ret; -} - - -/** - * Sign the message in @a purpose with the mint's signing key. - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the mint - * @param[out] sig signature over purpose using current signing key - */ -void -TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct TALER_MintPublicKeyP *pub, - struct TALER_MintSignatureP *sig) - -{ - struct TMH_KS_StateHandle *key_state; - - key_state = TMH_KS_acquire (); - *pub = key_state->current_sign_key_issue.issue.signkey_pub; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, - purpose, - &sig->eddsa_signature)); - TMH_KS_release (key_state); -} - - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_KS_handler_keys (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TMH_KS_StateHandle *key_state; - struct MHD_Response *response; - int ret; - - key_state = TMH_KS_acquire (); - response = MHD_create_response_from_buffer (strlen (key_state->keys_json), - key_state->keys_json, - MHD_RESPMEM_MUST_COPY); - TMH_KS_release (key_state); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - (void) MHD_add_response_header (response, - "Content-Type", - rh->mime_type); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/* end of taler-mint-httpd_keystate.c */ diff --git a/src/mint/taler-mint-httpd_keystate.h b/src/mint/taler-mint-httpd_keystate.h deleted file mode 100644 index 0e20ef588..000000000 --- a/src/mint/taler-mint-httpd_keystate.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/taler-mint-httpd_keystate.h - * @brief management of our private signing keys (denomination keys) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_KEYSTATE_H -#define TALER_MINT_HTTPD_KEYSTATE_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" -#include "taler_mintdb_lib.h" - - -/** - * Snapshot of the (coin and signing) - * keys (including private keys) of the mint. - */ -struct TMH_KS_StateHandle; - - -/** - * Acquire the key state of the mint. Updates keys if necessary. - * For every call to #TMH_KS_acquire(), a matching call - * to #TMH_KS_release() must be made. - * - * @param location name of the function in which the lock is acquired - * @return the key state - */ -struct TMH_KS_StateHandle * -TMH_KS_acquire_ (const char *location); - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * - * @param location name of the function in which the lock is acquired - * @param key_state the key state to release - */ -void -TMH_KS_release_ (const char *location, - struct TMH_KS_StateHandle *key_state); - - -/** - * Acquire the key state of the mint. Updates keys if necessary. - * For every call to #TMH_KS_acquire(), a matching call - * to #TMH_KS_release() must be made. - * - * @return the key state - */ -#define TMH_KS_acquire(void) TMH_KS_acquire_(__FUNCTION__) - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * - * @param key_state the key state to release - */ -#define TMH_KS_release(key_state) TMH_KS_release_ (__FUNCTION__, key_state) - - -/** - * Denomination key lookups can be for signing of fresh coins - * or to validate signatures on existing coins. As the validity - * periods for a key differ, the caller must specify which - * use is relevant for the current operation. - */ -enum TMH_KS_DenominationKeyUse { - - /** - * The key is to be used for a /reserve/withdraw or /refresh (mint) - * operation. - */ - TMH_KS_DKU_WITHDRAW, - - /** - * The key is to be usd for a /deposit or /refresh (melt) operation. - */ - TMH_KS_DKU_DEPOSIT - -}; - - -/** - * Look up the issue for a denom public key. Note that the result - * is only valid while the @a key_state is not released! - * - * @param key_state state to look in - * @param denom_pub denomination public key - * @param use purpose for which the key is being located - * @return the denomination key issue, - * or NULL if denom_pub could not be found (or is not valid at this time for the given @a use) - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - enum TMH_KS_DenominationKeyUse use); - - -/** - * Read signals from a pipe in a loop, and reload keys from disk if - * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and - * restart if SIGHUP is received. - * - * @return #GNUNET_SYSERR on errors, - * #GNUNET_OK to terminate normally - * #GNUNET_NO to restart an update version of the binary - */ -int -TMH_KS_loop (void); - - -/** - * Sign the message in @a purpose with the mint's signing - * key. - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the mint - * @param[out] sig signature over purpose using current signing key - */ -void -TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct TALER_MintPublicKeyP *pub, - struct TALER_MintSignatureP *sig); - - -/** - * Handle a "/keys" request - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_KS_handler_keys (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/mint/taler-mint-httpd_mhd.c b/src/mint/taler-mint-httpd_mhd.c deleted file mode 100644 index 5719d921a..000000000 --- a/src/mint/taler-mint-httpd_mhd.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_mhd.c - * @brief helpers for MHD interaction; these are TALER_MINT_handler_ functions - * that generate simple MHD replies that do not require any real operations - * to be performed (error handling, static pages, etc.) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd.h" -#include "taler-mint-httpd_mhd.h" - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct MHD_Response *response; - int ret; - - if (0 == rh->data_size) - rh->data_size = strlen ((const char *) rh->data); - response = MHD_create_response_from_buffer (rh->data_size, - (void *) rh->data, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Function to call to handle the request by sending - * back a redirect to the AGPL source code. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - const char *agpl = - "This server is licensed under the Affero GPL. You will now be redirected to the source code."; - struct MHD_Response *response; - int ret; - - response = MHD_create_response_from_buffer (strlen (agpl), - (void *) agpl, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - MHD_add_response_header (response, - MHD_HTTP_HEADER_LOCATION, - "http://www.git.taler.net/?p=mint.git"); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON - * reply with an error message from @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - return TMH_RESPONSE_reply_json_pack (connection, - rh->response_code, - "{s:s}", - "error", - rh->data); -} - - -/* end of taler-mint-httpd_mhd.c */ diff --git a/src/mint/taler-mint-httpd_mhd.h b/src/mint/taler-mint-httpd_mhd.h deleted file mode 100644 index a9f575df0..000000000 --- a/src/mint/taler-mint-httpd_mhd.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_mhd.h - * @brief helpers for MHD interaction, used to generate simple responses - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_MHD_H -#define TALER_MINT_HTTPD_MHD_H -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Function to call to handle the request by sending - * back a redirect to the AGPL source code. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Function to call to handle the request by building a JSON - * reply from varargs. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param response_code HTTP response code to use - * @param do_cache can the response be cached? (0: no, 1: yes) - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TMH_MHD_helper_send_json_pack (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void *connection_cls, - int response_code, - int do_cache, - const char *fmt, - ...); - - -/** - * Function to call to handle the request by building a JSON - * reply with an error message from @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c deleted file mode 100644 index 365202905..000000000 --- a/src/mint/taler-mint-httpd_parsing.c +++ /dev/null @@ -1,1137 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_parsing.c - * @brief functions to parse incoming requests (MHD arguments and JSON snippets) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ - -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" - - -/** - * Initial size for POST request buffer. - */ -#define REQUEST_BUFFER_INITIAL (2*1024) - -/** - * Maximum POST request size. - */ -#define REQUEST_BUFFER_MAX (1024*1024) - - -/** - * Buffer for POST requests. - */ -struct Buffer -{ - /** - * Allocated memory - */ - char *data; - - /** - * Number of valid bytes in buffer. - */ - size_t fill; - - /** - * Number of allocated bytes in buffer. - */ - size_t alloc; -}; - - -/** - * Initialize a buffer. - * - * @param buf the buffer to initialize - * @param data the initial data - * @param data_size size of the initial data - * @param alloc_size size of the buffer - * @param max_size maximum size that the buffer can grow to - * @return a GNUnet result code - */ -static int -buffer_init (struct Buffer *buf, - const void *data, - size_t data_size, - size_t alloc_size, - size_t max_size) -{ - if (data_size > max_size || alloc_size > max_size) - return GNUNET_SYSERR; - if (data_size > alloc_size) - alloc_size = data_size; - buf->data = GNUNET_malloc (alloc_size); - memcpy (buf->data, data, data_size); - return GNUNET_OK; -} - - -/** - * Free the data in a buffer. Does *not* free - * the buffer object itself. - * - * @param buf buffer to de-initialize - */ -static void -buffer_deinit (struct Buffer *buf) -{ - GNUNET_free (buf->data); - buf->data = NULL; -} - - -/** - * Append data to a buffer, growing the buffer if necessary. - * - * @param buf the buffer to append to - * @param data the data to append - * @param data_size the size of @a data - * @param max_size maximum size that the buffer can grow to - * @return #GNUNET_OK on success, - * #GNUNET_NO if the buffer can't accomodate for the new data - */ -static int -buffer_append (struct Buffer *buf, - const void *data, - size_t data_size, - size_t max_size) -{ - if (buf->fill + data_size > max_size) - return GNUNET_NO; - if (data_size + buf->fill > buf->alloc) - { - char *new_buf; - size_t new_size = buf->alloc; - while (new_size < buf->fill + data_size) - new_size += 2; - if (new_size > max_size) - return GNUNET_NO; - new_buf = GNUNET_malloc (new_size); - memcpy (new_buf, buf->data, buf->fill); - GNUNET_free (buf->data); - buf->data = new_buf; - buf->alloc = new_size; - } - memcpy (buf->data + buf->fill, data, data_size); - buf->fill += data_size; - return GNUNET_OK; -} - - -/** - * Release all memory allocated for the variable-size fields in - * the parser specification. - * - * @param spec specification to free - * @param spec_len number of items in @a spec to look at - */ -static void -release_data (struct TMH_PARSE_FieldSpecification *spec, - unsigned int spec_len) -{ - unsigned int i; - - for (i=0; i < spec_len; i++) - { - switch (spec[i].command) - { - case TMH_PARSE_JNC_FIELD: - GNUNET_break (0); - return; - case TMH_PARSE_JNC_INDEX: - GNUNET_break (0); - return; - case TMH_PARSE_JNC_RET_DATA: - break; - case TMH_PARSE_JNC_RET_DATA_VAR: - if (NULL != spec[i].destination) - { - GNUNET_free (* (void**) spec[i].destination); - *(void**) spec[i].destination = NULL; - *spec[i].destination_size_out = 0; - } - break; - case TMH_PARSE_JNC_RET_TYPED_JSON: - { - json_t *json; - - json = *(json_t **) spec[i].destination; - if (NULL != json) - { - json_decref (json); - *(json_t**) spec[i].destination = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - { - struct TALER_DenominationPublicKey *pk; - - pk = spec[i].destination; - if (NULL != pk->rsa_public_key) - { - GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key); - pk->rsa_public_key = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - { - struct TALER_DenominationSignature *sig; - - sig = spec[i].destination; - if (NULL != sig->rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature); - sig->rsa_signature = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_AMOUNT: - memset (spec[i].destination, - 0, - sizeof (struct TALER_Amount)); - break; - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - break; - case TMH_PARSE_JNC_RET_UINT64: - break; - } - } -} - - -/** - * Process a POST request containing a JSON object. This function - * realizes an MHD POST processor that will (incrementally) process - * JSON data uploaded to the HTTP server. It will store the required - * state in the @a con_cls, which must be cleaned up using - * #TMH_PARSE_post_cleanup_callback(). - * - * @param connection the MHD connection - * @param con_cls the closure (points to a `struct Buffer *`) - * @param upload_data the POST data - * @param upload_data_size number of bytes in @a upload_data - * @param json the JSON object for a completed request - * @return - * #GNUNET_YES if json object was parsed or at least - * may be parsed in the future (call again); - * `*json` will be NULL if we need to be called again, - * and non-NULL if we are done. - * #GNUNET_NO is request incomplete or invalid - * (error message was generated) - * #GNUNET_SYSERR on internal error - * (we could not even queue an error message, - * close HTTP session with MHD_NO) - */ -int -TMH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json) -{ - struct Buffer *r = *con_cls; - - *json = NULL; - if (NULL == *con_cls) - { - /* We are seeing a fresh POST request. */ - r = GNUNET_new (struct Buffer); - if (GNUNET_OK != - buffer_init (r, - upload_data, - *upload_data_size, - REQUEST_BUFFER_INITIAL, - REQUEST_BUFFER_MAX)) - { - *con_cls = NULL; - buffer_deinit (r); - GNUNET_free (r); - return (MHD_NO == - TMH_RESPONSE_reply_internal_error (connection, - "out of memory")) - ? GNUNET_SYSERR : GNUNET_NO; - } - /* everything OK, wait for more POST data */ - *upload_data_size = 0; - *con_cls = r; - return GNUNET_YES; - } - if (0 != *upload_data_size) - { - /* We are seeing an old request with more data available. */ - - if (GNUNET_OK != - buffer_append (r, - upload_data, - *upload_data_size, - REQUEST_BUFFER_MAX)) - { - /* Request too long */ - *con_cls = NULL; - buffer_deinit (r); - GNUNET_free (r); - return (MHD_NO == - TMH_RESPONSE_reply_request_too_large (connection)) - ? GNUNET_SYSERR : GNUNET_NO; - } - /* everything OK, wait for more POST data */ - *upload_data_size = 0; - return GNUNET_YES; - } - - /* We have seen the whole request. */ - - *json = json_loadb (r->data, - r->fill, - 0, - NULL); - if (NULL == *json) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to parse JSON request body\n"); - return (MHD_YES == - TMH_RESPONSE_reply_invalid_json (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - buffer_deinit (r); - GNUNET_free (r); - *con_cls = NULL; - - return GNUNET_YES; -} - - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TMH_PARSE_post_json(), to be cleaned up - */ -void -TMH_PARSE_post_cleanup_callback (void *con_cls) -{ - struct Buffer *r = con_cls; - - if (NULL != r) - { - buffer_deinit (r); - GNUNET_free (r); - } -} - - -/** - * Extract base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) -{ - const char *str; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TMH_RESPONSE_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out_data, - out_size)) - return (MHD_NO == - TMH_RESPONSE_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Extraxt variable-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing - * or the encoding is invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to allocate buffer and store the result - * @param[out] out_size set to the size of the buffer allocated in @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection, - const char *param_name, - void **out_data, - size_t *out_size) -{ - const char *str; - size_t slen; - size_t olen; - void *out; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TMH_RESPONSE_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - slen = strlen (str); - olen = (slen * 5) / 8; - out = GNUNET_malloc (olen); - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out, - olen)) - { - GNUNET_free (out); - *out_size = 0; - return (MHD_NO == - TMH_RESPONSE_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - *out_data = out; - *out_size = olen; - return GNUNET_OK; -} - - -/** - * Navigate through a JSON tree. - * - * Sends an error response if navigation is impossible (i.e. - * the JSON object is invalid) - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`) - * @return - * #GNUNET_YES if navigation was successful - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error (no response was generated, - * connection must be closed) - */ -int -TMH_PARSE_navigate_json (struct MHD_Connection *connection, - const json_t *root, - ...) -{ - va_list argp; - int ret; - json_t *path; /* what's our current path from 'root'? */ - - path = json_array (); - va_start (argp, root); - ret = 2; /* just not any of the valid return values */ - while (2 == ret) - { - enum TMH_PARSE_JsonNavigationCommand command - = va_arg (argp, - enum TMH_PARSE_JsonNavigationCommand); - - switch (command) - { - case TMH_PARSE_JNC_FIELD: - { - const char *fname = va_arg(argp, const char *); - - json_array_append_new (path, - json_string (fname)); - root = json_object_get (root, - fname); - if (NULL == root) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:O}", - "error", "missing field in JSON", - "field", fname, - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - break; - - case TMH_PARSE_JNC_INDEX: - { - int fnum = va_arg(argp, int); - - json_array_append_new (path, - json_integer (fnum)); - root = json_array_get (root, - fnum); - if (NULL == root) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "missing index in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - break; - - case TMH_PARSE_JNC_RET_DATA: - { - void *where = va_arg (argp, void *); - size_t len = va_arg (argp, size_t); - const char *str; - int res; - - str = json_string_value (root); - if (NULL == str) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - res = GNUNET_STRINGS_string_to_data (str, strlen (str), - where, len); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_DATA_VAR: - { - void **where = va_arg (argp, void **); - size_t *len = va_arg (argp, size_t *); - const char *str; - int res; - - str = json_string_value (root); - if (NULL == str) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "json_string_value() failed")) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *len = (strlen (str) * 5) / 8; - if (NULL != where) - { - *where = GNUNET_malloc (*len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - *where, - *len); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - GNUNET_free (*where); - *where = NULL; - *len = 0; - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_TYPED_JSON: - { - int typ = va_arg (argp, int); - const json_t **r_json = va_arg (argp, const json_t **); - - if ( (NULL == root) || - ( (-1 != typ) && - (json_typeof (root) != typ)) ) - { - GNUNET_break_op (0); - *r_json = NULL; - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:i, s:i, s:O}", - "error", "wrong JSON field type", - "type_expected", typ, - "type_actual", json_typeof (root), - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *r_json = root; - json_incref ((json_t *) root); - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_UINT64: - { - uint64_t *r_u64 = va_arg (argp, uint64_t *); - - if (json_typeof (root) != JSON_INTEGER) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:i, s:O}", - "error", "wrong JSON field type", - "type_expected", "integer", - "type_actual", json_typeof (root), - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *r_u64 = (uint64_t) json_integer_value (root); - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - { - struct TALER_DenominationPublicKey *where; - size_t len; - const char *str; - int res; - void *buf; - - where = va_arg (argp, - struct TALER_DenominationPublicKey *); - str = json_string_value (root); - if (NULL == str) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - len = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - len); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - GNUNET_free (buf); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf, - len); - GNUNET_free (buf); - if (NULL == where->rsa_public_key) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed RSA public key in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - { - struct TALER_DenominationSignature *where; - size_t len; - const char *str; - int res; - void *buf; - - where = va_arg (argp, - struct TALER_DenominationSignature *); - str = json_string_value (root); - if (NULL == str) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - len = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - len); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - GNUNET_free (buf); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf, - len); - GNUNET_free (buf); - if (NULL == where->rsa_signature) - { - GNUNET_break_op (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed RSA signature in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_AMOUNT: - { - struct TALER_Amount *where = va_arg (argp, void *); - - if (GNUNET_OK != - TALER_json_to_amount ((json_t *) root, - where)) - { - GNUNET_break_op (0); - ret = (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "Bad format", - "path", path)) - ? GNUNET_SYSERR : GNUNET_NO; - break; - } - if (0 != strcmp (where->currency, - TMH_mint_currency_string)) - { - GNUNET_break_op (0); - ret = (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O, s:s}", - "error", "Currency not supported", - "path", path, - "currency", where->currency)) - ? GNUNET_SYSERR : GNUNET_NO; - memset (where, 0, sizeof (struct TALER_Amount)); - break; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - { - struct GNUNET_TIME_Absolute *where = va_arg (argp, void *); - - if (GNUNET_OK != - TALER_json_to_abs ((json_t *) root, - where)) - { - GNUNET_break_op (0); - ret = (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:O}", - "error", "Bad format", - "hint", "expected absolute time", - "path", path)) - ? GNUNET_SYSERR : GNUNET_NO; - break; - } - ret = GNUNET_OK; - break; - } - - default: - GNUNET_break (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "unhandled value in switch")) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - va_end (argp); - json_decref (path); - return ret; -} - - -/** - * Parse JSON object into components based on the given field - * specification. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * #TMH_PARSE_release_data() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TMH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct TMH_PARSE_FieldSpecification *spec) -{ - unsigned int i; - int ret; - - ret = GNUNET_YES; - for (i=0; NULL != spec[i].field_name; i++) - { - if (GNUNET_YES != ret) - break; - switch (spec[i].command) - { - case TMH_PARSE_JNC_FIELD: - GNUNET_break (0); - return GNUNET_SYSERR; - case TMH_PARSE_JNC_INDEX: - GNUNET_break (0); - return GNUNET_SYSERR; - case TMH_PARSE_JNC_RET_DATA: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_DATA, - spec[i].destination, - spec[i].destination_size_in); - break; - case TMH_PARSE_JNC_RET_DATA_VAR: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_DATA_VAR, - (void **) spec[i].destination, - spec[i].destination_size_out); - break; - case TMH_PARSE_JNC_RET_TYPED_JSON: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_TYPED_JSON, - spec[i].type, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_RSA_SIGNATURE, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_AMOUNT: - GNUNET_assert (sizeof (struct TALER_Amount) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_AMOUNT, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_TIME_ABSOLUTE, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_UINT64: - GNUNET_assert (sizeof (uint64_t) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_UINT64, - spec[i].destination); - break; - } - } - if (GNUNET_YES != ret) - release_data (spec, - i - 1); - return ret; -} - - -/** - * Release all memory allocated for the variable-size fields in - * the parser specification. - * - * @param spec specification to free - */ -void -TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec) -{ - unsigned int i; - - for (i=0; NULL != spec[i].field_name; i++) ; - release_data (spec, i); -} - - -/** - * Generate line in parser specification for 64-bit integer - * given as an integer in JSON. - * - * @param field name of the field - * @param[out] u64 integer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_uint64 (const char *field, - uint64_t *u64) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 }; - return ret; -} - - -/** - * Generate line in parser specification for JSON object value. - * - * @param field name of the field - * @param[out] jsonp address of pointer to JSON to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_object (const char *field, - json_t **jsonp) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT }; - *jsonp = NULL; - return ret; -} - - -/** - * Generate line in parser specification for JSON array value. - * - * @param field name of the field - * @param[out] jsonp address of JSON pointer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_array (const char *field, - json_t **jsonp) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY }; - *jsonp = NULL; - return ret; -} - - -/** - * Generate line in parser specification for an absolute time. - * - * @param field name of the field - * @param[out] atime time to initialize - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_time_abs (const char *field, - struct GNUNET_TIME_Absolute *atime) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 }; - return ret; -} - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param[out] pk key to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_public_key (const char *field, - struct TALER_DenominationPublicKey *pk) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 }; - pk->rsa_public_key = NULL; - return ret; -} - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param sig the signature to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_signature (const char *field, - struct TALER_DenominationSignature *sig) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 }; - sig->rsa_signature = NULL; - return ret; -} - - -/** - * Generate line in parser specification for an amount. - * - * @param field name of the field - * @param amount a `struct TALER_Amount *` to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_amount (const char *field, - struct TALER_Amount *amount) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 }; - memset (amount, 0, sizeof (struct TALER_Amount)); - return ret; -} - - -/** - * Generate line in parser specification for variable-size value. - * - * @param field name of the field - * @param[out] ptr pointer to initialize - * @param[out] ptr_size size to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_variable (const char *field, - void **ptr, - size_t *ptr_size) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 }; - *ptr = NULL; - return ret; -} - -/* end of taler-mint-httpd_parsing.c */ diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h deleted file mode 100644 index a2cf4c469..000000000 --- a/src/mint/taler-mint-httpd_parsing.h +++ /dev/null @@ -1,408 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_parsing.h - * @brief functions to parse incoming requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_PARSING_H -#define TALER_MINT_HTTPD_PARSING_H - -#include <microhttpd.h> -#include <jansson.h> -#include "taler_util.h" - - -/** - * Process a POST request containing a JSON object. This - * function realizes an MHD POST processor that will - * (incrementally) process JSON data uploaded to the HTTP - * server. It will store the required state in the - * "connection_cls", which must be cleaned up using - * #TMH_PARSE_post_cleanup_callback(). - * - * @param connection the MHD connection - * @param con_cls the closure (points to a `struct Buffer *`) - * @param upload_data the POST data - * @param upload_data_size number of bytes in @a upload_data - * @param json the JSON object for a completed request - * @return - * #GNUNET_YES if json object was parsed or at least - * may be parsed in the future (call again); - * `*json` will be NULL if we need to be called again, - * and non-NULL if we are done. - * #GNUNET_NO is request incomplete or invalid - * (error message was generated) - * #GNUNET_SYSERR on internal error - * (we could not even queue an error message, - * close HTTP session with MHD_NO) - */ -int -TMH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json); - - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TMH_PARSE_post_json(), to be cleaned up - */ -void -TMH_PARSE_post_cleanup_callback (void *con_cls); - - -/** - * Constants for JSON navigation description. - */ -enum TMH_PARSE_JsonNavigationCommand -{ - /** - * Access a field. - * Param: const char * - */ - TMH_PARSE_JNC_FIELD, - - /** - * Access an array index. - * Param: int - */ - TMH_PARSE_JNC_INDEX, - - /** - * Return base32crockford encoded data of - * constant size. - * Params: (void *, size_t) - */ - TMH_PARSE_JNC_RET_DATA, - - /** - * Return base32crockford encoded data of - * variable size. - * Params: (void **, size_t *) - */ - TMH_PARSE_JNC_RET_DATA_VAR, - - /** - * Return a json object, which must be - * of the given type (JSON_* type constants, - * or -1 for any type). - * Params: (int, json_t **) - */ - TMH_PARSE_JNC_RET_TYPED_JSON, - - /** - * Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was - * encoded as variable-size base32crockford encoded data. - */ - TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, - - /** - * Return a `struct GNUNET_CRYPTO_rsa_Signature` which was - * encoded as variable-size base32crockford encoded data. - */ - TMH_PARSE_JNC_RET_RSA_SIGNATURE, - - /** - * Return a `struct TALER_Amount` which was - * encoded within its own json object. - */ - TMH_PARSE_JNC_RET_AMOUNT, - - /** - * Return a `struct GNUNET_TIME_Absolute` which was - * encoded within its own json object. - * Param: struct GNUNET_TIME_Absolute * - */ - TMH_PARSE_JNC_RET_TIME_ABSOLUTE, - - /** - * Return a `uint64_t` which was - * encoded as a JSON integer. - * Param: uint64_t * - */ - TMH_PARSE_JNC_RET_UINT64 - -}; - - -/** - * Navigate through a JSON tree. - * - * Sends an error response if navigation is impossible (i.e. - * the JSON object is invalid) - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`) - * @return - * #GNUNET_YES if navigation was successful - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TMH_PARSE_navigate_json (struct MHD_Connection *connection, - const json_t *root, - ...); - - -/** - * @brief Specification for how to parse a JSON field. - */ -struct TMH_PARSE_FieldSpecification -{ - /** - * Name of the field. NULL only to terminate array. - */ - const char *field_name; - - /** - * Where to store the result. Must have exactly - * @e destination_size bytes, except if @e destination_size is zero. - * NULL to skip assignment (but check presence of the value). - */ - void *destination; - - /** - * How big should the result be, 0 for variable size. In - * this case, @e destination must be a "void **", pointing - * to a location that is currently NULL and is to be allocated. - */ - size_t destination_size_in; - - /** - * @e destination_size_out will then be set to the size of the - * value that was stored in @e destination (useful for - * variable-size allocations). - */ - size_t *destination_size_out; - - /** - * Navigation command to use to extract the value. Note that - * #TMH_PARSE_JNC_RET_DATA or #TMH_PARSE_JNC_RET_DATA_VAR must be used for @e - * destination_size_in and @e destination_size_out to have a - * meaning. #TMH_PARSE_JNC_FIELD and #TMH_PARSE_JNC_INDEX must not be used here! - */ - enum TMH_PARSE_JsonNavigationCommand command; - - /** - * JSON type to use, only meaningful in connection with a @e command - * value of #TMH_PARSE_JNC_RET_TYPED_JSON. Typical values are - * #JSON_ARRAY and #JSON_OBJECT. - */ - int type; - -}; - - -/** - * Parse JSON object into components based on the given field - * specification. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * #TMH_PARSE_release_data() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TMH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct TMH_PARSE_FieldSpecification *spec); - - -/** - * Release all memory allocated for the variable-size fields in - * the parser specification. - * - * @param spec specification to free - */ -void -TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec); - - -/** - * Generate line in parser specification for fixed-size value. - * - * @param field name of the field - * @param value where to store the value - */ -#define TMH_PARSE_member_fixed(field,value) { field, value, sizeof (*value), NULL, TMH_PARSE_JNC_RET_DATA, 0 } - - -/** - * Generate line in parser specification for variable-size value. - * - * @param field name of the field - * @param[out] ptr pointer to initialize - * @param[out] ptr_size size to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_variable (const char *field, - void **ptr, - size_t *ptr_size); - - -/** - * Generate line in parser specification for 64-bit integer - * given as an integer in JSON. - * - * @param field name of the field - * @param[out] u64 integer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_uint64 (const char *field, - uint64_t *u64); - - -/** - * Generate line in parser specification for JSON array value. - * - * @param field name of the field - * @param[out] jsonp address of JSON pointer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_array (const char *field, - json_t **jsonp); - - -/** - * Generate line in parser specification for JSON object value. - * - * @param field name of the field - * @param[out] jsonp address of pointer to JSON to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_object (const char *field, - json_t **jsonp); - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param[out] pk key to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_public_key (const char *field, - struct TALER_DenominationPublicKey *pk); - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param sig the signature to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_signature (const char *field, - struct TALER_DenominationSignature *sig); - - -/** - * Generate line in parser specification for an amount. - * - * @param field name of the field - * @param[out] amount a `struct TALER_Amount *` to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_amount (const char *field, - struct TALER_Amount *amount); - - -/** - * Generate line in parser specification for an absolute time. - * - * @param field name of the field - * @param[out] atime time to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_time_abs (const char *field, - struct GNUNET_TIME_Absolute *atime); - - - -/** - * Generate line in parser specification indicating the end of the spec. - */ -#define TMH_PARSE_MEMBER_END { NULL, NULL, 0, NULL, TMH_PARSE_JNC_FIELD, 0 } - - -/** - * Extraxt fixed-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size); - - -/** - * Extraxt variable-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing - * or the encoding is invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to allocate buffer and store the result - * @param[out] out_size set to the size of the buffer allocated in @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection, - const char *param_name, - void **out_data, - size_t *out_size); - - - - -#endif /* TALER_MINT_HTTPD_PARSING_H */ diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c deleted file mode 100644 index 4d89fe892..000000000 --- a/src/mint/taler-mint-httpd_refresh.c +++ /dev/null @@ -1,911 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_refresh.c - * @brief Handle /refresh/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_mhd.h" -#include "taler-mint-httpd_refresh.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * Handle a "/refresh/melt" request after the main JSON parsing has happened. - * We now need to validate the coins being melted and the session signature - * and then hand things of to execute the melt operation. - * - * @param connection the MHD connection to handle - * @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array - * @param denom_pubs array of @a num_new_denoms keys - * @param coin_count number of coins to be melted, size of y-dimension of @a commit_coin array - * @param coin_melt_details array with @a coin_count entries with melting details - * @param session_hash hash over the data that the client commits to - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done) - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * @return MHD result code - */ -static int -handle_refresh_melt_binary (struct MHD_Connection *connection, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - const struct GNUNET_HashCode *session_hash, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_RefreshCommitLinkP *const* commit_link) -{ - unsigned int i; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_DenominationKeyIssueInformation *dk; - struct TALER_MINTDB_DenominationKeyInformationP *dki; - struct TALER_Amount cost; - struct TALER_Amount total_cost; - struct TALER_Amount melt; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_melt; - struct TALER_Amount total_melt; - - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TMH_mint_currency_string, - &total_cost)); - key_state = TMH_KS_acquire (); - for (i=0;i<num_new_denoms;i++) - { - dk = TMH_KS_denomination_key_lookup (key_state, - &denom_pubs[i], - TMH_KS_DKU_WITHDRAW); - if (NULL == dk) - { - GNUNET_break_op (0); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_arg_invalid (connection, - "new_denoms"); - } - dki = &dk->issue; - TALER_amount_ntoh (&value, - &dki->properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->properties.fee_withdraw); - if ( (GNUNET_OK != - TALER_amount_add (&cost, - &value, - &fee_withdraw)) || - (GNUNET_OK != - TALER_amount_add (&total_cost, - &cost, - &total_cost)) ) - { - GNUNET_break_op (0); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_error (connection, - "cost calculation failure"); - } - } - - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TMH_mint_currency_string, - &total_melt)); - for (i=0;i<coin_count;i++) - { - /* calculate contribution of the i-th melt by subtracting - the fee; add the rest to the total_melt value */ - dk = TMH_KS_denomination_key_lookup (key_state, - &coin_melt_details[i].coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dk) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_arg_invalid (connection, - "denom_pub"); - } - dki = &dk->issue; - TALER_amount_ntoh (&fee_melt, - &dki->properties.fee_refresh); - if (GNUNET_OK != - TALER_amount_subtract (&melt, - &coin_melt_details->melt_amount_with_fee, - &fee_melt)) - { - GNUNET_break_op (0); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_external_error (connection, - "Melt contribution below melting fee"); - } - if (GNUNET_OK != - TALER_amount_add (&total_melt, - &melt, - &total_melt)) - { - GNUNET_break_op (0); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - } - } - TMH_KS_release (key_state); - if (0 != - TALER_amount_cmp (&total_cost, - &total_melt)) - { - GNUNET_break_op (0); - /* We require total value of coins being melted and - total value of coins being generated to match! */ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "value mismatch"); - } - return TMH_DB_execute_refresh_melt (connection, - session_hash, - num_new_denoms, - denom_pubs, - coin_count, - coin_melt_details, - commit_coin, - commit_link); -} - - -/** - * Extract public coin information from a JSON object. - * - * @param connection the connection to send error responses to - * @param coin_info the JSON object to extract the coin info from - * @param[out] r_melt_detail set to details about the coin's melting permission (if valid) - * @return #GNUNET_YES if coin public info in JSON was valid - * #GNUNET_NO JSON was invalid, response was generated - * #GNUNET_SYSERR on internal error - */ -static int -get_coin_public_info (struct MHD_Connection *connection, - json_t *coin_info, - struct TMH_DB_MeltDetails *r_melt_detail) -{ - int ret; - struct TALER_CoinSpendSignatureP melt_sig; - struct TALER_DenominationSignature sig; - struct TALER_DenominationPublicKey pk; - struct TALER_Amount amount; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub), - TMH_PARSE_member_denomination_signature ("denom_sig", &sig), - TMH_PARSE_member_denomination_public_key ("denom_pub", &pk), - TMH_PARSE_member_fixed ("confirm_sig", &melt_sig), - TMH_PARSE_member_amount ("value_with_fee", &amount), - TMH_PARSE_MEMBER_END - }; - - ret = TMH_PARSE_json_data (connection, - coin_info, - spec); - if (GNUNET_OK != ret) - { - GNUNET_break_op (0); - return ret; - } - /* check mint signature on the coin */ - r_melt_detail->coin_info.denom_sig = sig; - r_melt_detail->coin_info.denom_pub = pk; - if (GNUNET_OK != - TALER_test_coin_valid (&r_melt_detail->coin_info)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - r_melt_detail->coin_info.denom_sig.rsa_signature = NULL; - r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL; - return (MHD_YES == - TMH_RESPONSE_reply_signature_invalid (connection, - "denom_sig")) - ? GNUNET_NO : GNUNET_SYSERR; - } - r_melt_detail->melt_sig = melt_sig; - r_melt_detail->melt_amount_with_fee = amount; - return GNUNET_OK; -} - - -/** - * Verify that the signature shows that this coin is to be melted into - * the given @a session_hash melting session, and that this is a valid - * coin (we know the denomination key and the signature on it is - * valid). Essentially, this does all of the per-coin checks that can - * be done before the transaction starts. - * - * @param connection the connection to send error responses to - * @param session_hash hash over refresh session the coin is melted into - * @param[in,out] melt_detail details about the coin's melting permission, - * the `melt_fee` is updated - * @return #GNUNET_YES if coin public info in JSON was valid - * #GNUNET_NO JSON was invalid, response was generated - * #GNUNET_SYSERR on internal error - */ -static int -verify_coin_public_info (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - struct TMH_DB_MeltDetails *melt_detail) -{ - struct TALER_RefreshMeltCoinAffirmationPS body; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_Amount fee_refresh; - - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - &melt_detail->coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (key_state); - TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - TALER_amount_ntoh (&fee_refresh, - &dki->issue.properties.fee_refresh); - melt_detail->melt_fee = fee_refresh; - body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); - body.session_hash = *session_hash; - TALER_amount_hton (&body.amount_with_fee, - &melt_detail->melt_amount_with_fee); - TALER_amount_hton (&body.melt_fee, - &fee_refresh); - body.coin_pub = melt_detail->coin_info.coin_pub; - if (TALER_amount_cmp (&fee_refresh, - &melt_detail->melt_amount_with_fee) > 0) - { - GNUNET_break_op (0); - TMH_KS_release (key_state); - return (MHD_YES == - TMH_RESPONSE_reply_external_error (connection, - "melt amount smaller than melting fee")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - TMH_KS_release (key_state); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &body.purpose, - &melt_detail->melt_sig.eddsa_signature, - &melt_detail->coin_info.coin_pub.eddsa_pub)) - { - GNUNET_break_op (0); - if (MHD_YES != - TMH_RESPONSE_reply_signature_invalid (connection, - "confirm_sig")) - return GNUNET_SYSERR; - return GNUNET_NO; - } - return GNUNET_OK; -} - - -/** - * Release memory from the @a commit_coin array. - * - * @param commit_coin array to release - * @param kappa size of 1st dimension - * @param num_new_coins size of 2nd dimension - */ -static void -free_commit_coins (struct TALER_MINTDB_RefreshCommitCoin **commit_coin, - unsigned int kappa, - unsigned int num_new_coins) -{ - unsigned int i; - unsigned int j; - - for (i=0;i<kappa;i++) - { - if (NULL == commit_coin[i]) - break; - for (j=0;j<num_new_coins;j++) - { - GNUNET_free_non_null (commit_coin[i][j].coin_ev); - GNUNET_free_non_null (commit_coin[i][j].refresh_link); - } - GNUNET_free (commit_coin[i]); - } -} - - -/** - * Release memory from the @a commit_link array. - * - * @param commit_link array to release - * @param kappa size of 1st dimension - * @param num_old_coins size of 2nd dimension - */ -static void -free_commit_links (struct TALER_RefreshCommitLinkP **commit_link, - unsigned int kappa, - unsigned int num_old_coins) -{ - unsigned int i; - - for (i=0;i<kappa;i++) - { - if (NULL == commit_link[i]) - break; - GNUNET_free (commit_link[i]); - } -} - - -/** - * Handle a "/refresh/melt" request after the first parsing has happened. - * We now need to validate the coins being melted and the session signature - * and then hand things of to execute the melt operation. This function - * parses the JSON arrays and then passes processing on to - * #handle_refresh_melt_binary(). - * - * @param connection the MHD connection to handle - * @param new_denoms array of denomination keys - * @param melt_coins array of coins to melt - * @param num_oldcoins number of coins that are being melted - * @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins transfer keys - * @param secret_encs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins secrets - * @param num_newcoins number of coins that the refresh will generate - * @param coin_evs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins envelopes to sign - * @param link_encs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins encrypted links - * @return MHD result code - */ -static int -handle_refresh_melt_json (struct MHD_Connection *connection, - const json_t *new_denoms, - const json_t *melt_coins, - unsigned int num_oldcoins, - const json_t *transfer_pubs, - const json_t *secret_encs, - unsigned int num_newcoins, - const json_t *coin_evs, - const json_t *link_encs) -{ - int res; - unsigned int i; - unsigned int j; - struct TALER_DenominationPublicKey *denom_pubs; - unsigned int num_new_denoms; - struct TMH_DB_MeltDetails *coin_melt_details; - unsigned int coin_count; - struct GNUNET_HashCode session_hash; - struct GNUNET_HashContext *hash_context; - struct TALER_MINTDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA]; - struct TALER_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA]; - - /* For the signature check, we hash most of the inputs together - (except for the signatures on the coins). */ - hash_context = GNUNET_CRYPTO_hash_context_start (); - num_new_denoms = json_array_size (new_denoms); - denom_pubs = GNUNET_malloc (num_new_denoms * - sizeof (struct TALER_DenominationPublicKey)); - for (i=0;i<num_new_denoms;i++) - { - char *buf; - size_t buf_size; - - res = TMH_PARSE_navigate_json (connection, - new_denoms, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, - &denom_pubs[i].rsa_public_key); - if (GNUNET_OK != res) - { - res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; - goto cleanup_denoms; - } - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key, - &buf); - GNUNET_CRYPTO_hash_context_read (hash_context, - buf, - buf_size); - GNUNET_free (buf); - } - - coin_count = json_array_size (melt_coins); - coin_melt_details = GNUNET_new_array (coin_count, - struct TMH_DB_MeltDetails); - for (i=0;i<coin_count;i++) - { - /* decode JSON data on coin to melt */ - struct TALER_AmountNBO melt_amount; - - res = get_coin_public_info (connection, - json_array_get (melt_coins, i), - &coin_melt_details[i]); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; - goto cleanup_melt_details; - } - /* Check that the client does not try to melt the same coin twice - into the same session! */ - for (j=0;j<i;j++) - { - if (0 == memcmp (&coin_melt_details[i].coin_info.coin_pub, - &coin_melt_details[j].coin_info.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))) - { - GNUNET_break_op (0); - res = TMH_RESPONSE_reply_external_error (connection, - "melting same coin twice in same session is not allowed"); - goto cleanup_melt_details; - } - } - TALER_amount_hton (&melt_amount, - &coin_melt_details[i].melt_amount_with_fee); - GNUNET_CRYPTO_hash_context_read (hash_context, - &coin_melt_details[i].coin_info.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - GNUNET_CRYPTO_hash_context_read (hash_context, - &melt_amount, - sizeof (struct TALER_AmountNBO)); - } - - /* parse JSON arrays into 2d binary arrays and hash everything - together for the signature check */ - memset (commit_coin, 0, sizeof (commit_coin)); - memset (commit_link, 0, sizeof (commit_link)); - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - commit_coin[i] = GNUNET_malloc (num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - for (j = 0; j < num_newcoins; j++) - { - char *link_enc; - size_t link_enc_size; - struct TALER_MINTDB_RefreshCommitCoin *rcc = &commit_coin[i][j]; - - res = TMH_PARSE_navigate_json (connection, - coin_evs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA_VAR, - &rcc->coin_ev, - &rcc->coin_ev_size); - - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - goto cleanup; - } - - GNUNET_CRYPTO_hash_context_read (hash_context, - rcc->coin_ev, - rcc->coin_ev_size); - res = TMH_PARSE_navigate_json (connection, - link_encs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA_VAR, - &link_enc, - &link_enc_size); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - goto cleanup; - } - rcc->refresh_link - = TALER_refresh_link_encrypted_decode (link_enc, - link_enc_size); - GNUNET_CRYPTO_hash_context_read (hash_context, - link_enc, - link_enc_size); - GNUNET_free (link_enc); - } - } - - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - commit_link[i] = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_RefreshCommitLinkP)); - for (j = 0; j < num_oldcoins; j++) - { - struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j]; - - res = TMH_PARSE_navigate_json (connection, - transfer_pubs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &rcl->transfer_pub, - sizeof (struct TALER_TransferPublicKeyP)); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - goto cleanup; - } - res = TMH_PARSE_navigate_json (connection, - secret_encs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &rcl->shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP)); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - goto cleanup; - } - GNUNET_CRYPTO_hash_context_read (hash_context, - rcl, - sizeof (struct TALER_RefreshCommitLinkP)); - } - } - GNUNET_CRYPTO_hash_context_finish (hash_context, - &session_hash); - hash_context = NULL; - for (i=0;i<coin_count;i++) - { - /* verify signatures on coins to melt */ - res = verify_coin_public_info (connection, - &session_hash, - &coin_melt_details[i]); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; - goto cleanup; - } - } - - /* execute commit */ - res = handle_refresh_melt_binary (connection, - num_new_denoms, - denom_pubs, - coin_count, - coin_melt_details, - &session_hash, - commit_coin, - commit_link); - cleanup: - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - free_commit_links (commit_link, - TALER_CNC_KAPPA, - num_oldcoins); - cleanup_melt_details: - for (j=0;j<coin_count;j++) - { - if (NULL != coin_melt_details[j].coin_info.denom_pub.rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key); - if (NULL != coin_melt_details[j].coin_info.denom_sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature); - } - GNUNET_free (coin_melt_details); - cleanup_denoms: - for (j=0;j<num_new_denoms;j++) - if (NULL != denom_pubs[j].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - if (NULL != hash_context) - GNUNET_CRYPTO_hash_context_abort (hash_context); - return res; -} - - -/** - * Handle a "/refresh/melt" request. Parses the request into the JSON - * components and then hands things of to #handle_refresh_melt_json() - * to validate the melted coins, the signature and execute the melt - * using TMH_DB_execute_refresh_melt(). - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *root; - json_t *new_denoms; - json_t *melt_coins; - json_t *coin_evs; - json_t *link_encs; - json_t *transfer_pubs; - json_t *secret_encs; - unsigned int num_oldcoins; - unsigned int num_newcoins; - json_t *coin_detail; - int res; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_array ("new_denoms", &new_denoms), - TMH_PARSE_member_array ("melt_coins", &melt_coins), - TMH_PARSE_member_array ("coin_evs", &coin_evs), - TMH_PARSE_member_array ("link_encs", &link_encs), - TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs), - TMH_PARSE_member_array ("secret_encs", &secret_encs), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - - /* Determine dimensionality of the request (kappa, #old and #new coins) */ - if (TALER_CNC_KAPPA != json_array_size (coin_evs)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "coin_evs"); - } - if (TALER_CNC_KAPPA != json_array_size (transfer_pubs)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "transfer_pubs"); - } - res = TMH_PARSE_navigate_json (connection, - coin_evs, - TMH_PARSE_JNC_INDEX, (int) 0, - TMH_PARSE_JNC_RET_TYPED_JSON, - JSON_ARRAY, &coin_detail); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_newcoins = json_array_size (coin_detail); - json_decref (coin_detail); - res = TMH_PARSE_navigate_json (connection, - transfer_pubs, - TMH_PARSE_JNC_INDEX, (int) 0, - TMH_PARSE_JNC_RET_TYPED_JSON, - JSON_ARRAY, &coin_detail); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_oldcoins = json_array_size (coin_detail); - json_decref (coin_detail); - res = handle_refresh_melt_json (connection, - new_denoms, - melt_coins, - num_oldcoins, - transfer_pubs, - secret_encs, - num_newcoins, - coin_evs, - link_encs); - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/refresh/reveal" request. Parses the given JSON - * transfer private keys and if successful, passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param connection the MHD connection to handle - * @param session_hash hash identifying the melting session - * @param num_oldcoins length of the 2nd dimension of @a transfer_privs array - * @param tp_json private transfer keys in JSON format - * @return MHD result code - */ -static int -handle_refresh_reveal_json (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - const json_t *tp_json) -{ - struct TALER_TransferPrivateKeyP *transfer_privs[TALER_CNC_KAPPA - 1]; - unsigned int i; - unsigned int j; - int res; - - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - transfer_privs[i] = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_TransferPrivateKeyP)); - res = GNUNET_OK; - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - { - if (GNUNET_OK != res) - break; - for (j = 0; j < num_oldcoins; j++) - { - if (GNUNET_OK != res) - break; - res = TMH_PARSE_navigate_json (connection, - tp_json, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &transfer_privs[i][j], - sizeof (struct TALER_TransferPrivateKeyP)); - GNUNET_break_op (GNUNET_OK == res); - } - } - if (GNUNET_OK != res) - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - else - res = TMH_DB_execute_refresh_reveal (connection, - session_hash, - num_oldcoins, - transfer_privs); - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - GNUNET_free (transfer_privs[i]); - return res; -} - - -/** - * Handle a "/refresh/reveal" request. This time, the client reveals - * the private transfer keys except for the cut-and-choose value - * returned from "/refresh/melt". This function parses the revealed - * keys and secrets and ultimately passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct GNUNET_HashCode session_hash; - int res; - unsigned int num_oldcoins; - json_t *reveal_detail; - json_t *root; - json_t *transfer_privs; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("session_hash", &session_hash), - TMH_PARSE_member_array ("transfer_privs", &transfer_privs), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - { - GNUNET_break_op (0); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - /* Determine dimensionality of the request (kappa and #old coins) */ - /* Note we do +1 as 1 row (cut-and-choose!) is missing! */ - if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1) - { - TMH_PARSE_release_data (spec); - GNUNET_break_op (0); - return TMH_RESPONSE_reply_arg_invalid (connection, - "transfer_privs"); - } - res = TMH_PARSE_navigate_json (connection, - transfer_privs, - TMH_PARSE_JNC_INDEX, 0, - TMH_PARSE_JNC_RET_TYPED_JSON, - JSON_ARRAY, - &reveal_detail); - if (GNUNET_OK != res) - { - TMH_PARSE_release_data (spec); - GNUNET_break_op (0); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_oldcoins = json_array_size (reveal_detail); - json_decref (reveal_detail); - res = handle_refresh_reveal_json (connection, - &session_hash, - num_oldcoins, - transfer_privs); - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/refresh/link" request. Note that for "/refresh/link" - * we do use a simple HTTP GET, and a HTTP POST! - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_CoinSpendPublicKeyP coin_pub; - int res; - - res = TMH_PARSE_mhd_request_arg_data (connection, - "coin_pub", - &coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - if (GNUNET_SYSERR == res) - return MHD_NO; - if (GNUNET_OK != res) - return MHD_YES; - return TMH_DB_execute_refresh_link (connection, - &coin_pub); -} - - -/* end of taler-mint-httpd_refresh.c */ diff --git a/src/mint/taler-mint-httpd_refresh.h b/src/mint/taler-mint-httpd_refresh.h deleted file mode 100644 index 8fe12a272..000000000 --- a/src/mint/taler-mint-httpd_refresh.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_refresh.h - * @brief Handle /refresh/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_REFRESH_H -#define TALER_MINT_HTTPD_REFRESH_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/refresh/melt" request. Parses the request into the JSON - * components and then hands things of to #handle_refresh_melt_json() - * to validate the melted coins, the signature and execute the melt - * using TMH_DB_execute_refresh_melt(). - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/refresh/reveal" request. This time, the client reveals - * the private transfer keys except for the cut-and-choose value - * returned from "/refresh/commit". This function parses the revealed - * keys and secrets and ultimately passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/refresh/link" request - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/mint/taler-mint-httpd_reserve.c b/src/mint/taler-mint-httpd_reserve.c deleted file mode 100644 index c887ee750..000000000 --- a/src/mint/taler-mint-httpd_reserve.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014,2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_reserve.c - * @brief Handle /reserve/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler-mint-httpd_reserve.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * Handle a "/reserve/status" request. Parses the - * given "reserve_pub" argument (which should contain the - * EdDSA public key of a reserve) and then respond with the - * status of the reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_ReservePublicKeyP reserve_pub; - int res; - - res = TMH_PARSE_mhd_request_arg_data (connection, - "reserve_pub", - &reserve_pub, - sizeof (struct TALER_ReservePublicKeyP)); - if (GNUNET_SYSERR == res) - return MHD_NO; /* internal error */ - if (GNUNET_NO == res) - return MHD_YES; /* parse error */ - return TMH_DB_execute_reserve_status (connection, - &reserve_pub); -} - - -/** - * Handle a "/reserve/withdraw" request. Parses the "reserve_pub" - * EdDSA key of the reserve and the requested "denom_pub" which - * specifies the key/value of the coin to be withdrawn, and checks - * that the signature "reserve_sig" makes this a valid withdrawl - * request from the specified reserve. If so, the envelope - * with the blinded coin "coin_ev" is passed down to execute the - * withdrawl operation. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *root; - struct TALER_WithdrawRequestPS wsrd; - int res; - struct TALER_DenominationPublicKey denomination_pub; - char *blinded_msg; - size_t blinded_msg_len; - struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; - struct TALER_Amount fee_withdraw; - struct TALER_ReserveSignatureP signature; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TMH_KS_StateHandle *ks; - - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("coin_ev", - (void **) &blinded_msg, - &blinded_msg_len), - TMH_PARSE_member_fixed ("reserve_pub", - &wsrd.reserve_pub), - TMH_PARSE_member_fixed ("reserve_sig", - &signature), - TMH_PARSE_member_denomination_public_key ("denom_pub", - &denomination_pub), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - ks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (ks, - &denomination_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - TMH_PARSE_release_data (spec); - TMH_KS_release (ks); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - TALER_amount_ntoh (&amount, - &dki->issue.properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&amount_with_fee, - &amount, - &fee_withdraw)); - TALER_amount_hton (&wsrd.amount_with_fee, - &amount_with_fee); - TALER_amount_hton (&wsrd.withdraw_fee, - &fee_withdraw); - TMH_KS_release (ks); - /* verify signature! */ - wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - - GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key, - &wsrd.h_denomination_pub); - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &wsrd.h_coin_envelope); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, - &wsrd.purpose, - &signature.eddsa_signature, - &wsrd.reserve_pub.eddsa_pub)) - { - TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n"); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_signature_invalid (connection, - "reserve_sig"); - } - res = TMH_DB_execute_reserve_withdraw (connection, - &wsrd.reserve_pub, - &denomination_pub, - blinded_msg, - blinded_msg_len, - &signature); - TMH_PARSE_release_data (spec); - return res; -} - -/* end of taler-mint-httpd_reserve.c */ diff --git a/src/mint/taler-mint-httpd_reserve.h b/src/mint/taler-mint-httpd_reserve.h deleted file mode 100644 index 71a779fe3..000000000 --- a/src/mint/taler-mint-httpd_reserve.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_reserve.h - * @brief Handle /reserve/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_RESERVE_H -#define TALER_MINT_HTTPD_RESERVE_H - -#include <microhttpd.h> -#include "taler-mint-httpd.h" - -/** - * Handle a "/reserve/status" request. Parses the - * given "reserve_pub" argument (which should contain the - * EdDSA public key of a reserve) and then respond with the - * status of the reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_RESERVE_handler_reserve_status (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/reserve/withdraw" request. Parses the "reserve_pub" - * EdDSA key of the reserve and the requested "denom_pub" which - * specifies the key/value of the coin to be withdrawn, and checks - * that the signature "reserve_sig" makes this a valid withdrawl - * request from the specified reserve. If so, the envelope - * with the blinded coin "coin_ev" is passed down to execute the - * withdrawl operation. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c deleted file mode 100644 index 2ebd0d331..000000000 --- a/src/mint/taler-mint-httpd_responses.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_responses.c - * @brief API for generating the various replies of the mint; these - * functions are called TMH_RESPONSE_reply_ and they generate - * and queue MHD response objects for a given connection. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler-mint-httpd_responses.h" -#include "taler_util.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler-mint-httpd_keystate.h" - - -/** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TMH_RESPONSE_add_global_headers (struct MHD_Response *response) -{ - if (TMH_mint_connection_close) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONNECTION, - "close"); -} - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TMH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code) -{ - struct MHD_Response *resp; - char *json_str; - int ret; - - json_str = json_dumps (json, JSON_INDENT(2)); - GNUNET_assert (NULL != json_str); - resp = MHD_create_response_from_buffer (strlen (json_str), json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == resp) - { - free (json_str); - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (resp); - (void) MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json"); - ret = MHD_queue_response (connection, - response_code, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...) -{ - json_t *json; - va_list argp; - int ret; - json_error_t jerror; - - va_start (argp, fmt); - json = json_vpack_ex (&jerror, 0, fmt, argp); - va_end (argp); - if (NULL == json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to pack JSON with format `%s': %s\n", - fmt, - jerror.text); - GNUNET_break (0); - return MHD_NO; - } - ret = TMH_RESPONSE_reply_json (connection, - json, - response_code); - json_decref (json); - return ret; -} - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", - "error", "invalid parameter", - "parameter", param_name); -} - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the mint (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:s}", - "error", "unknown entity referenced", - "parameter", param_name); -} - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s, s:s}", - "error", "invalid signature", - "parameter", param_name); -} - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{ s:s, s:s}", - "error", "missing parameter", - "parameter", param_name); -} - - -/** - * Send a response indicating permission denied. - * - * @param connection the MHD connection to use - * @param hint hint about why access was denied - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, - const char *hint) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:s}", - "error", "permission denied", - "hint", hint); -} - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - const char *hint) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:s}", - "error", "internal error", - "hint", hint); -} - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - const char *hint) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", - "error", "client error", - "hint", hint); -} - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "commit failure"); -} - - -/** - * Send a response indicating a failure to talk to the Mint's - * database. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to connect to database"); -} - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection) -{ - struct MHD_Response *resp; - int ret; - - resp = MHD_create_response_from_buffer (0, - NULL, - MHD_RESPMEM_PERSISTENT); - if (NULL == resp) - return MHD_NO; - TMH_RESPONSE_add_global_headers (resp); - ret = MHD_queue_response (connection, - MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "invalid json"); -} - - -/** - * Send confirmation of deposit success to client. This function - * will create a signed message affirming the given information - * and return it to the client. By this, the mint affirms that - * the coin had sufficient (residual) value for the specified - * transaction and that it will execute the requested deposit - * operation with the given wiring details. - * - * @param connection connection to the client - * @param coin_pub public key of the coin - * @param h_wire hash of wire details - * @param h_contract hash of contract details - * @param transaction_id transaction ID - * @param timestamp client's timestamp - * @param refund_deadline until when this deposit be refunded - * @param merchant merchant public key - * @param amount_without_fee fraction of coin value to deposit, without the fee - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - struct GNUNET_TIME_Absolute timestamp, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_MerchantPublicKeyP *merchant, - const struct TALER_Amount *amount_without_fee) -{ - struct TALER_DepositConfirmationPS dc; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - - dc.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT); - dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); - dc.h_contract = *h_contract; - dc.h_wire = *h_wire; - dc.transaction_id = GNUNET_htonll (transaction_id); - dc.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - TALER_amount_hton (&dc.amount_without_fee, - amount_without_fee); - dc.coin_pub = *coin_pub; - dc.merchant = *merchant; - TMH_KS_sign (&dc.purpose, - &pub, - &sig); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s, s:o, s:o}", - "status", "DEPOSIT_OK", - "sig", TALER_json_from_data (&sig, - sizeof (sig)), - "pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * Compile the transaction history of a coin into a JSON object. - * - * @param tl transaction history to JSON-ify - * @return json representation of the @a rh - */ -static json_t * -compile_transaction_history (const struct TALER_MINTDB_TransactionList *tl) -{ - json_t *details; - const char *type; - struct TALER_Amount value; - json_t *history; - const struct TALER_CoinSpendSignatureP *sig; - const struct TALER_MINTDB_TransactionList *pos; - - history = json_array (); - for (pos = tl; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_TT_DEPOSIT: - { - struct TALER_DepositRequestPS dr; - const struct TALER_MINTDB_Deposit *deposit = pos->details.deposit; - - type = "DEPOSIT"; - value = deposit->amount_with_fee; - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = deposit->h_contract; - dr.h_wire = deposit->h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); - dr.transaction_id = GNUNET_htonll (deposit->transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - &deposit->amount_with_fee); - TALER_amount_hton (&dr.deposit_fee, - &deposit->deposit_fee); - dr.merchant = deposit->merchant_pub; - dr.coin_pub = deposit->coin.coin_pub; - sig = &deposit->csig; - /* internal sanity check before we hand out a bogus sig... */ - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &sig->eddsa_signature, - &deposit->coin.coin_pub.eddsa_pub)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - - details = TALER_json_from_data (&dr.purpose, - sizeof (struct TALER_DepositRequestPS)); - break; - } - case TALER_MINTDB_TT_REFRESH_MELT: - { - struct TALER_RefreshMeltCoinAffirmationPS ms; - const struct TALER_MINTDB_RefreshMelt *melt = pos->details.melt; - - type = "MELT"; - value = melt->amount_with_fee; - ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); - ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - ms.session_hash = melt->session_hash; - TALER_amount_hton (&ms.amount_with_fee, - &melt->amount_with_fee); - TALER_amount_hton (&ms.melt_fee, - &melt->melt_fee); - ms.coin_pub = melt->coin.coin_pub; - sig = &melt->coin_sig; - /* internal sanity check before we hand out a bogus sig... */ - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &ms.purpose, - &sig->eddsa_signature, - &melt->coin.coin_pub.eddsa_pub)) - { - GNUNET_break (0); - json_decref (history); - return NULL; - } - - details = TALER_json_from_data (&ms.purpose, - sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - } - break; - default: - GNUNET_assert (0); - } - json_array_append_new (history, - json_pack ("{s:s, s:o, s:o, s:o}", - "type", type, - "amount", TALER_json_from_amount (&value), - "signature", TALER_json_from_data (sig, - sizeof (struct TALER_CoinSpendSignatureP)), - "details", details)); - } - return history; -} - - -/** - * Send proof that a /deposit request is invalid to client. This - * function will create a message with all of the operations affecting - * the coin that demonstrate that the coin has insufficient value. - * - * @param connection connection to the client - * @param tl transaction list to use to build reply - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_TransactionList *tl) -{ - json_t *history; - - history = compile_transaction_history (tl); - if (NULL == history) - return TMH_RESPONSE_reply_internal_db_error (connection); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:o}", - "error", "insufficient funds", - "history", history); -} - - -/** - * Compile the history of a reserve into a JSON object - * and calculate the total balance. - * - * @param rh reserve history to JSON-ify - * @param[out] balance set to current reserve balance - * @return json representation of the @a rh, NULL on error - */ -static json_t * -compile_reserve_history (const struct TALER_MINTDB_ReserveHistory *rh, - struct TALER_Amount *balance) -{ - struct TALER_Amount deposit_total; - struct TALER_Amount withdraw_total; - struct TALER_Amount value; - json_t *json_history; - int ret; - const struct TALER_MINTDB_ReserveHistory *pos; - struct TALER_WithdrawRequestPS wr; - - json_history = json_array (); - ret = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - if (0 == ret) - deposit_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.bank->amount)) - { - json_decref (json_history); - return NULL; - } - ret = 1; - json_array_append_new (json_history, - json_pack ("{s:s, s:O, s:o}", - "type", "DEPOSIT", - "wire", pos->details.bank->wire, - "amount", TALER_json_from_amount (&pos->details.bank->amount))); - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - break; - } - } - - ret = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - value = pos->details.withdraw->amount_with_fee; - if (0 == ret) - { - withdraw_total = value; - } - else - { - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &value)) - { - json_decref (json_history); - return NULL; - } - } - ret = 1; - wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - wr.reserve_pub = pos->details.withdraw->reserve_pub; - TALER_amount_hton (&wr.amount_with_fee, - &value); - TALER_amount_hton (&wr.withdraw_fee, - &pos->details.withdraw->withdraw_fee); - GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key, - &wr.h_denomination_pub); - wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope; - json_array_append_new (json_history, - json_pack ("{s:s, s:o, s:o, s:o}", - "type", "WITHDRAW", - "signature", TALER_json_from_data (&pos->details.withdraw->reserve_sig, - sizeof (struct TALER_ReserveSignatureP)), - "details", TALER_json_from_data (&wr, - sizeof (wr)), - "amount", TALER_json_from_amount (&value))); - break; - } - } - if (0 == ret) - { - /* did not encounter any withdraw operations, set to zero */ - TALER_amount_get_zero (deposit_total.currency, - &withdraw_total); - } - if (GNUNET_SYSERR == - TALER_amount_subtract (balance, - &deposit_total, - &withdraw_total)) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - - return json_history; -} - - -/** - * Send reserve status information to client. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - json_balance = TALER_json_from_amount (&balance); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "balance", json_balance, - "history", json_history); -} - - -/** - * Send reserve status information to client with the - * message that we have insufficient funds for the - * requested /reserve/withdraw operation. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - json_balance = TALER_json_from_amount (&balance); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_PAYMENT_REQUIRED, - "{s:s, s:o, s:o}", - "error", "Insufficient funds", - "balance", json_balance, - "history", json_history); -} - - -/** - * Send blinded coin information to client. - * - * @param connection connection to the client - * @param collectable blinded coin to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_CollectableBlindcoin *collectable) -{ - json_t *sig_json; - - sig_json = TALER_json_from_rsa_signature (collectable->sig.rsa_signature); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ev_sig", sig_json); -} - - -/** - * Send a response for a failed "/refresh/melt" request. The - * transaction history of the given coin demonstrates that the - * @a residual value of the coin is below the @a requested - * contribution of the coin for the melt. Thus, the mint - * refuses the melt operation. - * - * @param connection the connection to send the response to - * @param coin_pub public key of the coin - * @param coin_value original value of the coin - * @param tl transaction history for the coin - * @param requested how much this coin was supposed to contribute, including fee - * @param residual remaining value of the coin (after subtracting @a tl) - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_Amount coin_value, - struct TALER_MINTDB_TransactionList *tl, - struct TALER_Amount requested, - struct TALER_Amount residual) -{ - json_t *history; - - history = compile_transaction_history (tl); - if (NULL == history) - return TMH_RESPONSE_reply_internal_db_error (connection); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:o, s:o, s:o, s:o, s:o}", - "error", - "insufficient funds", - "coin_pub", - TALER_json_from_data (coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)), - "original_value", - TALER_json_from_amount (&coin_value), - "residual_value", - TALER_json_from_amount (&residual), - "requested_value", - TALER_json_from_amount (&requested), - "history", - history); -} - - -/** - * Send a response to a "/refresh/melt" request. - * - * @param connection the connection to send the response to - * @param session_hash hash of the refresh session - * @param noreveal_index which index will the client not have to reveal - * @return a MHD status code - */ -int -TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - uint16_t noreveal_index) -{ - struct TALER_RefreshMeltConfirmationPS body; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - json_t *sig_json; - - body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS)); - body.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_MELT); - body.session_hash = *session_hash; - body.noreveal_index = htons (noreveal_index); - body.reserved = htons (0); - TMH_KS_sign (&body.purpose, - &pub, - &sig); - sig_json = TALER_json_from_data (&sig, - sizeof (sig)); - GNUNET_assert (NULL != sig_json); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:i, s:o, s:o}", - "noreveal_index", (int) noreveal_index, - "mint_sig", sig_json, - "mint_pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * Send a response for "/refresh/reveal". - * - * @param connection the connection to send the response to - * @param num_newcoins number of new coins for which we reveal data - * @param sigs array of @a num_newcoins signatures revealed - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection, - unsigned int num_newcoins, - const struct TALER_DenominationSignature *sigs) -{ - int newcoin_index; - json_t *root; - json_t *obj; - json_t *list; - int ret; - - list = json_array (); - for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++) - { - obj = json_object (); - json_object_set_new (obj, - "ev_sig", - TALER_json_from_rsa_signature (sigs[newcoin_index].rsa_signature)); - json_array_append_new (list, - obj); - } - root = json_object (); - json_object_set_new (root, - "ev_sigs", - list); - ret = TMH_RESPONSE_reply_json (connection, - root, - MHD_HTTP_OK); - json_decref (root); - return ret; -} - - -/** - * Send a response for a failed "/refresh/reveal", where the - * revealed value(s) do not match the original commitment. - * - * @param connection the connection to send the response to - * @param mc all information about the original commitment - * @param off offset in the array of kappa-commitments where - * the missmatch was detected - * @param j index of the coin for which the missmatch was - * detected - * @param missmatch_object name of the object that was - * bogus (i.e. "transfer key"). - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, - const struct TALER_MINTDB_MeltCommitment *mc, - unsigned int off, - unsigned int j, - const char *missmatch_object) -{ - json_t *info_old; - json_t *info_new; - json_t *info_commit; - json_t *info_links; - unsigned int i; - unsigned int k; - - info_old = json_array (); - for (i=0;i<mc->num_oldcoins;i++) - { - const struct TALER_MINTDB_RefreshMelt *rm; - json_t *rm_json; - - rm = &mc->melts[i]; - rm_json = json_object (); - json_object_set_new (rm_json, - "coin_sig", - TALER_json_from_data (&rm->coin_sig, - sizeof (struct TALER_CoinSpendSignatureP))); - json_object_set_new (rm_json, - "coin_pub", - TALER_json_from_data (&rm->coin.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))); - json_object_set_new (rm_json, - "melt_amount_with_fee", - TALER_json_from_amount (&rm->amount_with_fee)); - json_object_set_new (rm_json, - "melt_fee", - TALER_json_from_amount (&rm->melt_fee)); - json_array_append_new (info_old, - rm_json); - } - info_new = json_array (); - for (i=0;i<mc->num_newcoins;i++) - { - const struct TALER_DenominationPublicKey *pk; - - pk = &mc->denom_pubs[i]; - json_array_append_new (info_new, - TALER_json_from_rsa_public_key (pk->rsa_public_key)); - - } - info_commit = json_array (); - info_links = json_array (); - for (k=0;k<TALER_CNC_KAPPA;k++) - { - json_t *info_commit_k; - json_t *info_link_k; - - info_commit_k = json_array (); - for (i=0;i<mc->num_newcoins;i++) - { - const struct TALER_MINTDB_RefreshCommitCoin *cc; - json_t *cc_json; - - cc = &mc->commit_coins[k][i]; - cc_json = json_object (); - json_object_set_new (cc_json, - "coin_ev", - TALER_json_from_data (cc->coin_ev, - cc->coin_ev_size)); - json_object_set_new (cc_json, - "coin_priv_enc", - TALER_json_from_data (cc->refresh_link->coin_priv_enc, - sizeof (struct TALER_CoinSpendPrivateKeyP))); - json_object_set_new (cc_json, - "blinding_key_enc", - TALER_json_from_data (cc->refresh_link->blinding_key_enc, - cc->refresh_link->blinding_key_enc_size)); - - json_array_append_new (info_commit_k, - cc_json); - } - json_array_append_new (info_commit, - info_commit_k); - info_link_k = json_array (); - for (i=0;i<mc->num_oldcoins;i++) - { - const struct TALER_RefreshCommitLinkP *cl; - json_t *cl_json; - - cl = &mc->commit_links[k][i]; - cl_json = json_object (); - json_object_set_new (cl_json, - "transfer_pub", - TALER_json_from_data (&cl->transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))); - json_object_set_new (cl_json, - "shared_secret_enc", - TALER_json_from_data (&cl->shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP))); - json_array_append_new (info_link_k, - cl_json); - } - json_array_append_new (info_links, - info_link_k); - } - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_CONFLICT, - "{s:s, s:i, s:i, s:o, s:o, s:o, s:o, s:s}", - "error", "commitment violation", - "offset", (int) off, - "index", (int) j, - "oldcoin_infos", info_old, - "newcoin_infos", info_new, - "commit_infos", info_commit, - "link_infos", info_links, - "object", missmatch_object); -} - - -/** - * Send a response for "/refresh/link". - * - * @param connection the connection to send the response to - * @param num_sessions number of sessions the coin was used in - * @param sessions array of @a num_session entries with - * information for each session - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, - unsigned int num_sessions, - const struct TMH_RESPONSE_LinkSessionInfo *sessions) -{ - json_t *root; - json_t *mlist; - int res; - unsigned int i; - - mlist = json_array (); - for (i=0;i<num_sessions;i++) - { - const struct TALER_MINTDB_LinkDataList *pos; - json_t *list = json_array (); - - for (pos = sessions[i].ldl; NULL != pos; pos = pos->next) - { - json_t *obj; - - obj = json_object (); - json_object_set_new (obj, - "link_enc", - TALER_json_from_data (pos->link_data_enc->coin_priv_enc, - sizeof (struct TALER_CoinSpendPrivateKeyP) + - pos->link_data_enc->blinding_key_enc_size)); - json_object_set_new (obj, - "denom_pub", - TALER_json_from_rsa_public_key (pos->denom_pub.rsa_public_key)); - json_object_set_new (obj, - "ev_sig", - TALER_json_from_rsa_signature (pos->ev_sig.rsa_signature)); - json_array_append_new (list, - obj); - } - root = json_object (); - json_object_set_new (root, - "new_coins", - list); - json_object_set_new (root, - "transfer_pub", - TALER_json_from_data (&sessions[i].transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))); - json_object_set_new (root, - "secret_enc", - TALER_json_from_data (&sessions[i].shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP))); - json_array_append_new (mlist, - root); - } - res = TMH_RESPONSE_reply_json (connection, - mlist, - MHD_HTTP_OK); - json_decref (mlist); - return res; -} - - -/** - * A merchant asked for details about a deposit, but - * we do not know anything about the deposit. Generate the - * 404 reply. - * - * @param connection connection to the client - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "Deposit unknown"); -} - - -/** - * A merchant asked for details about a deposit, but - * we did not execute the deposit yet. Generate a 202 reply. - * - * @param connection connection to the client - * @param planned_exec_time planned execution time - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, - struct GNUNET_TIME_Absolute planned_exec_time) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_ACCEPTED, - "{s:o}", - "execution_time", TALER_json_from_abs (planned_exec_time)); -} - - -/** - * A merchant asked for details about a deposit. Provide - * them. Generates the 200 reply. - * - * @param connection connection to the client - * @param h_contract hash of the contract - * @param h_wire hash of wire account details - * @param coin_pub public key of the coin - * @param coin_contribution how much did the coin we asked about - * contribute to the total transfer value? (deposit value minus fee) - * @param transaction_id merchant transaction identifier - * @param wtid raw wire transfer identifier - * @param exec_time execution time of the wire transfer - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_contribution, - uint64_t transaction_id, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute exec_time) -{ - struct TALER_ConfirmWirePS cw; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - - cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE); - cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS)); - cw.h_wire = *h_wire; - cw.h_contract = *h_contract; - cw.wtid = *wtid; - cw.coin_pub = *coin_pub; - cw.transaction_id = GNUNET_htonll (transaction_id); - cw.execution_time = GNUNET_TIME_absolute_hton (exec_time); - TALER_amount_hton (&cw.coin_contribution, - coin_contribution); - TMH_KS_sign (&cw.purpose, - &pub, - &sig); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o, s:o}", - "wtid", TALER_json_from_data (wtid, - sizeof (*wtid)), - "execution_time", TALER_json_from_abs (exec_time), - "coin_contribution", TALER_json_from_amount (coin_contribution), - "mint_sig", TALER_json_from_data (&sig, - sizeof (sig)), - "mint_pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * A merchant asked for transaction details about a wire transfer. - * Provide them. Generates the 200 reply. - * - * @param connection connection to the client - * @param total total amount that was transferred - * @param merchant_pub public key of the merchant - * @param h_wire destination account - * @param deposits details about the combined deposits - * @return MHD result code - */ -int -TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, - const struct TALER_Amount *total, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - json_t *deposits) -{ - /* FIXME: #4135: signing not implemented here */ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o}", - "total", TALER_json_from_amount (total), - "merchant_pub", TALER_json_from_data (merchant_pub, - sizeof (struct TALER_MerchantPublicKeyP)), - "h_wire", TALER_json_from_data (h_wire, - sizeof (struct GNUNET_HashCode)), - "deposits", deposits); -} - - -/* end of taler-mint-httpd_responses.c */ diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h deleted file mode 100644 index a0396c8a1..000000000 --- a/src/mint/taler-mint-httpd_responses.h +++ /dev/null @@ -1,469 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_responses.h - * @brief API for generating the various replies of the mint; these - * functions are called TMH_RESPONSE_reply_ and they generate - * and queue MHD response objects for a given connection. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_RESPONSES_H -#define TALER_MINT_HTTPD_RESPONSES_H -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd.h" -#include "taler-mint-httpd_db.h" - -/** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TMH_RESPONSE_add_global_headers (struct MHD_Response *response); - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TMH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code); - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...); - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - const char *param_name); - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return MHD result code - */ -int -TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - const char *param_name); - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the mint (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - const char *param_name); - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - const char *param_name); - - -/** - * Send a response indicating permission denied. - * - * @param connection the MHD connection to use - * @param hint hint about why access was denied - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, - const char *hint); - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - const char *hint); - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - const char *hint); - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection); - - -/** - * Send a response indicating a failure to talk to the Mint's - * database. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection); - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection); - - -/** - * Send confirmation of deposit success to client. This function - * will create a signed message affirming the given information - * and return it to the client. By this, the mint affirms that - * the coin had sufficient (residual) value for the specified - * transaction and that it will execute the requested deposit - * operation with the given wiring details. - * - * @param connection connection to the client - * @param coin_pub public key of the coin - * @param h_wire hash of wire details - * @param h_contract hash of contract details - * @param transaction_id transaction ID - * @param timestamp client's timestamp - * @param refund_deadline until when this deposit be refunded - * @param merchant merchant public key - * @param amount_without_fee fraction of coin value to deposit (without fee) - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - struct GNUNET_TIME_Absolute timestamp, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_MerchantPublicKeyP *merchant, - const struct TALER_Amount *amount_without_fee); - - -/** - * Send proof that a /deposit request is invalid to client. This - * function will create a message with all of the operations affecting - * the coin that demonstrate that the coin has insufficient value. - * - * @param connection connection to the client - * @param tl transaction list to use to build reply - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_TransactionList *tl); - - -/** - * A merchant asked for details about a deposit, but - * we do not know anything about the deposit. Generate the - * 404 reply. - * - * @param connection connection to the client - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection); - - -/** - * A merchant asked for details about a deposit, but - * we did not execute the deposit yet. Generate a 202 reply. - * - * @param connection connection to the client - * @param planned_exec_time planned execution time - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, - struct GNUNET_TIME_Absolute planned_exec_time); - - -/** - * A merchant asked for details about a deposit. Provide - * them. Generates the 200 reply. - * - * @param connection connection to the client - * @param h_contract hash of the contract - * @param h_wire hash of wire account details - * @param coin_pub public key of the coin - * @param coin_contribution contribution of this coin to the total amount transferred - * @param transaction_id merchant transaction identifier - * @param wtid raw wire transfer identifier - * @param exec_time execution time of the wire transfer - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_contribution, - uint64_t transaction_id, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute exec_time); - - -/** - * A merchant asked for transaction details about a wire transfer. - * Provide them. Generates the 200 reply. - * - * @param connection connection to the client - * @param total total amount that was transferred - * @param merchant_pub public key of the merchant - * @param h_wire destination account - * @param deposits details about the combined deposits - * @return MHD result code - */ -int -TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection, - const struct TALER_Amount *total, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - json_t *deposits); - - -/** - * Send reserve status information to client. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_status_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh); - - -/** - * Send reserve status information to client with the - * message that we have insufficient funds for the - * requested /reserve/withdraw operation. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh); - - -/** - * Send blinded coin information to client. - * - * @param connection connection to the client - * @param collectable blinded coin to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_reserve_withdraw_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_CollectableBlindcoin *collectable); - - -/** - * Send a confirmation response to a "/refresh/melt" request. - * - * @param connection the connection to send the response to - * @param session_hash hash of the refresh session - * @param noreveal_index which index will the client not have to reveal - * @return a MHD status code - */ -int -TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - uint16_t noreveal_index); - - -/** - * Send a response for a failed "/refresh/melt" request. The - * transaction history of the given coin demonstrates that the - * @a residual value of the coin is below the @a requested - * contribution of the coin for the melt. Thus, the mint - * refuses the melt operation. - * - * @param connection the connection to send the response to - * @param coin_pub public key of the coin - * @param coin_value original value of the coin - * @param tl transaction history for the coin - * @param requested how much this coin was supposed to contribute - * @param residual remaining value of the coin (after subtracting @a tl) - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_Amount coin_value, - struct TALER_MINTDB_TransactionList *tl, - struct TALER_Amount requested, - struct TALER_Amount residual); - - -/** - * Send a response for "/refresh/reveal". - * - * @param connection the connection to send the response to - * @param num_newcoins number of new coins for which we reveal data - * @param sigs array of @a num_newcoins signatures revealed - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection, - unsigned int num_newcoins, - const struct TALER_DenominationSignature *sigs); - - -/** - * Send a response for a failed "/refresh/reveal", where the - * revealed value(s) do not match the original commitment. - * - * @param connection the connection to send the response to - * @param mc all information about the original commitment - * @param off offset in the array of kappa-commitments where - * the missmatch was detected - * @param j index of the coin for which the missmatch was - * detected - * @param missmatch_object name of the object that was - * bogus (i.e. "transfer key"). - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, - const struct TALER_MINTDB_MeltCommitment *mc, - unsigned int off, - unsigned int j, - const char *missmatch_object); - - -/** - * @brief Information for each session a coin was melted into. - */ -struct TMH_RESPONSE_LinkSessionInfo -{ - /** - * Transfer public key of the coin. - */ - struct TALER_TransferPublicKeyP transfer_pub; - - /** - * Encrypted shared secret for decrypting the transfer secrets. - */ - struct TALER_EncryptedLinkSecretP shared_secret_enc; - - /** - * Linked data of coins being created in the session. - */ - struct TALER_MINTDB_LinkDataList *ldl; - -}; - - -/** - * Send a response for "/refresh/link". - * - * @param connection the connection to send the response to - * @param num_sessions number of sessions the coin was used in - * @param sessions array of @a num_session entries with - * information for each session - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, - unsigned int num_sessions, - const struct TMH_RESPONSE_LinkSessionInfo *sessions); - - -#endif diff --git a/src/mint/taler-mint-httpd_test.c b/src/mint/taler-mint-httpd_test.c deleted file mode 100644 index b894854f3..000000000 --- a/src/mint/taler-mint-httpd_test.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_test.c - * @brief Handle /test requests; parses the POST and JSON and - * checks that the client is binary-compatible - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include "taler_signatures.h" -#include "taler-mint-httpd_test.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" - - -/** - * Private key the test module uses for signing. - */ -static struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_pk; - - -/** - * Handle a "/test/base32" request. Parses the JSON in the post, runs - * the Crockford Base32 decoder on the "input" field in the JSON, - * hashes the result and sends the hashed value back as a JSON - * string with in Base32 Crockford encoding. Thus, this API - * allows testing the hashing and Crockford encoding/decoding - * functions. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - void *in_ptr; - size_t in_ptr_size; - struct GNUNET_HashCode hc; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - GNUNET_CRYPTO_hash (in_ptr, - in_ptr_size, - &hc); - TMH_PARSE_release_data (spec); - json_decref (json); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - TALER_json_from_data (&hc, sizeof (struct GNUNET_HashCode))); -} - - -/** - * Handle a "/test/encrypt" request. Parses the JSON in the post, - * runs the Crockford Base32 decoder on the "input" field in the JSON, - * and encrypts the result with a shared secret derived using the HKDF - * function with salt "skey" and IV derived with salt "iv" of the - * Crockford Base32-encoded "key_hash" field in the JSON. The - * symmetric encryption is the AES/Twofish double-encryption used in - * Taler/GNUnet. The resulting ciphertext is returned as a Crockford - * Base32 encoded JSON string. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct GNUNET_HashCode key; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct GNUNET_CRYPTO_SymmetricSessionKey skey; - void *in_ptr; - size_t in_ptr_size; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), - TMH_PARSE_member_fixed ("key_hash", &key), - TMH_PARSE_MEMBER_END - }; - char *out; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - GNUNET_assert (GNUNET_YES == - GNUNET_CRYPTO_kdf (&skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), - "skey", strlen ("skey"), - &key, sizeof (key), - NULL, 0)); - GNUNET_assert (GNUNET_YES == - GNUNET_CRYPTO_kdf (&iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector), - "iv", strlen ("iv"), - &key, sizeof (key), - NULL, 0)); - out = GNUNET_malloc (in_ptr_size); - GNUNET_break (in_ptr_size == - GNUNET_CRYPTO_symmetric_encrypt (in_ptr, - in_ptr_size, - &skey, - &iv, - out)); - json = TALER_json_from_data (out, - in_ptr_size); - GNUNET_free (out); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - json); -} - - -/** - * Handle a "/test/hkdf" request. Parses the JSON in the post, runs - * the Crockford Base32 decoder on the "input" field in the JSON, - * computes `HKDF(input, "salty")` and sends the result back as a JSON - * string with in Base32 Crockford encoding. Thus, this API allows - * testing the use of the (H)KDF. Note that the test fixes the - * input and output sizes and the salt (and the hash functions used - * by the HKDF), so this is only useful to test the HKDF in the - * same way it will be used within Taler/GNUnet. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct GNUNET_HashCode hc; - void *in_ptr; - size_t in_ptr_size; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - GNUNET_CRYPTO_kdf (&hc, sizeof (hc), - "salty", strlen ("salty"), - in_ptr, - in_ptr_size, - NULL, 0); - TMH_PARSE_release_data (spec); - json = TALER_json_from_data (&hc, - sizeof (struct GNUNET_HashCode)); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - json); -} - - -/** - * Handle a "/test/ecdhe" request. Parses the JSON in the post, which - * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv" - * with a private key. The reply is the resulting JSON is an object - * with the field "ecdh_hash" containing a Crockford Base32-encoded - * string representing the hash derived via ECDH of the two keys. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct GNUNET_CRYPTO_EcdhePublicKey pub; - struct GNUNET_CRYPTO_EcdhePrivateKey priv; - struct GNUNET_HashCode hc; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("ecdhe_pub", &pub), - TMH_PARSE_member_fixed ("ecdhe_priv", &priv), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - if (GNUNET_OK != - GNUNET_CRYPTO_ecc_ecdh (&priv, - &pub, - &hc)) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to perform ECDH"); - } - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ecdh_hash", - TALER_json_from_data (&hc, - sizeof (hc))); -} - - -/** - * Handle a "/test/eddsa" request. Parses the JSON in the post, - * which must contain a "eddsa_pub" with a public key and an - *"eddsa_sig" with the corresponding signature for a purpose - * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is - * valid, a reply with a #TALER_SIGNATURE_MINT_TEST_EDDSA is - * returned using the same JSON format. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct GNUNET_CRYPTO_EddsaPublicKey pub; - struct GNUNET_CRYPTO_EddsaSignature sig; - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("eddsa_pub", &pub), - TMH_PARSE_member_fixed ("eddsa_sig", &sig), - TMH_PARSE_MEMBER_END - }; - struct GNUNET_CRYPTO_EddsaPrivateKey *pk; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); - purpose.purpose = htonl (TALER_SIGNATURE_CLIENT_TEST_EDDSA); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_CLIENT_TEST_EDDSA, - &purpose, - &sig, - &pub)) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_signature_invalid (connection, - "eddsa_sig"); - } - TMH_PARSE_release_data (spec); - pk = GNUNET_CRYPTO_eddsa_key_create (); - purpose.purpose = htonl (TALER_SIGNATURE_MINT_TEST_EDDSA); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_sign (pk, - &purpose, - &sig)) - { - GNUNET_free (pk); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to EdDSA-sign"); - } - GNUNET_CRYPTO_eddsa_key_get_public (pk, - &pub); - GNUNET_free (pk); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "eddsa_pub", - TALER_json_from_data (&pub, - sizeof (pub)), - "eddsa_sig", - TALER_json_from_data (&sig, - sizeof (sig))); -} - - -/** - * Handle a "/test/rsa/get" request. Returns the RSA public key - * ("rsa_pub") which is used for signing in "/test/rsa/sign". - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - int res; - struct GNUNET_CRYPTO_rsa_PublicKey *pub; - - if (NULL == rsa_pk) - rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024); - if (NULL == rsa_pk) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to create RSA key"); - } - pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk); - if (NULL == pub) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to get public RSA key"); - } - res = TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "rsa_pub", - TALER_json_from_rsa_public_key (pub)); - GNUNET_CRYPTO_rsa_public_key_free (pub); - return res; -} - - -/** - * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which - * must contain an "blind_ev" blinded value. A a blinded signature - * ("rsa_blind_sig") is returned. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct GNUNET_CRYPTO_rsa_Signature *sig; - void *in_ptr; - size_t in_ptr_size; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("blind_ev", &in_ptr, &in_ptr_size), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - if (NULL == rsa_pk) - rsa_pk = GNUNET_CRYPTO_rsa_private_key_create (1024); - if (NULL == rsa_pk) - { - GNUNET_break (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to create RSA key"); - } - sig = GNUNET_CRYPTO_rsa_sign (rsa_pk, - in_ptr, - in_ptr_size); - if (NULL == sig) - { - GNUNET_break (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to RSA-sign"); - } - TMH_PARSE_release_data (spec); - res = TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "rsa_blind_sig", - TALER_json_from_rsa_signature (sig)); - GNUNET_CRYPTO_rsa_signature_free (sig); - return res; -} - - -/** - * Handle a "/test/transfer" request. Parses the JSON in the post, - * which must contain a "secret_enc" with the encrypted link secret, - * a "trans_priv" with the transfer private key, a "coin_pub" with - * a coin public key. A reply with the decrypted "secret" is - * returned. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - struct TALER_EncryptedLinkSecretP secret_enc; - struct TALER_TransferPrivateKeyP trans_priv; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("secret_enc", &secret_enc), - TMH_PARSE_member_fixed ("trans_priv", &trans_priv), - TMH_PARSE_member_fixed ("coin_pub", &coin_pub), - TMH_PARSE_MEMBER_END - }; - struct TALER_LinkSecretP secret; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - json_decref (json); - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - if (GNUNET_OK != - TALER_link_decrypt_secret (&secret_enc, - &trans_priv, - &coin_pub, - &secret)) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to decrypt secret"); - } - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "secret", - TALER_json_from_data (&secret, - sizeof (secret))); -} - - -/** - * Handle a "/test" request. Parses the JSON in the post. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - int res; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - - json_decref (json); - return MHD_NO; -} - - -/* end of taler-mint-httpd_test.c */ diff --git a/src/mint/taler-mint-httpd_test.h b/src/mint/taler-mint-httpd_test.h deleted file mode 100644 index 33844aab1..000000000 --- a/src/mint/taler-mint-httpd_test.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_test.h - * @brief Handle /test requests - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_TEST_H -#define TALER_MINT_HTTPD_TEST_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/test/base32" request. Parses the JSON in the post, runs - * the Crockford Base32 decoder on the "input" field in the JSON, - * hashes the result and sends the hashed value back as a JSON - * string with in Base32 Crockford encoding. Thus, this API - * allows testing the hashing and Crockford encoding/decoding - * functions. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/encrypt" request. Parses the JSON in the post, - * runs the Crockford Base32 decoder on the "input" field in the JSON, - * and encrypts the result with a shared secret derived using the HKDF - * function with salt "skey" and IV derived with salt "iv" of the - * Crockford Base32-encoded "key_hash" field in the JSON. The - * symmetric encryption is the AES/Twofish double-encryption used in - * Taler/GNUnet. The resulting ciphertext is returned as a Crockford - * Base32 encoded JSON string. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/hkdf" request. Parses the JSON in the post, runs - * the Crockford Base32 decoder on the "input" field in the JSON, - * computes `HKDF(input, "salty")` and sends the result back as a JSON - * string with in Base32 Crockford encoding. Thus, this API allows - * testing the use of the (H)KDF. Note that the test fixes the - * input and output sizes and the salt (and the hash functions used - * by the HKDF), so this is only useful to test the HKDF in the - * same way it will be used within Taler/GNUnet. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/ecdhe" request. Parses the JSON in the post, which - * must contain a "ecdhe_pub" with a public key and an "ecdhe_priv" - * with a private key. The reply is the resulting JSON is an object - * with the field "ecdh_hash" containing a Crockford Base32-encoded - * string representing the hash derived via ECDH of the two keys. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/eddsa" request. Parses the JSON in the post, - * which must contain a "eddsa_pub" with a public key and an - *"ecdsa_sig" with the corresponding signature for a purpose - * of #TALER_SIGNATURE_CLIENT_TEST_EDDSA. If the signature is - * valid, a reply with a #TALER_SIGNATURE_MINT_TEST_EDDSA is - * returned using the same JSON format. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/rsa/get" request. Returns the RSA public key - * ("rsa_pub") which is used for signing in "/test/rsa/sign". - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_rsa_get (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/rsa/sign" request. Parses the JSON in the post, which - * must contain an "blind_ev" blinded value. A a blinded signature - * ("rsa_blind_sig") is returned. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test/transfer" request. Parses the JSON in the post, - * which must contain a "secret_enc" with the encrypted link secret, - * a "trans_priv" with the transfer private key, a "coin_pub" with - * a coin public key. A reply with the decrypted "secret" is - * returned. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/test" request. Parses the JSON in the post. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TEST_handler_test (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c deleted file mode 100644 index a6b41cf86..000000000 --- a/src/mint/taler-mint-httpd_tracking.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_tracking.c - * @brief Handle wire transfer tracking-related requests - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler_signatures.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_tracking.h" -#include "taler-mint-httpd_responses.h" - - -/** - * Handle a "/wire/deposits" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_WireTransferIdentifierRawP wtid; - int res; - - res = TMH_PARSE_mhd_request_arg_data (connection, - "wtid", - &wtid, - sizeof (struct TALER_WireTransferIdentifierRawP)); - if (GNUNET_SYSERR == res) - return MHD_NO; /* internal error */ - if (GNUNET_NO == res) - return MHD_YES; /* parse error */ - return TMH_DB_execute_wire_deposits (connection, - &wtid); -} - - -/** - * Check the merchant signature, and if it is valid, - * return the wire transfer identifier. - * - * @param connection the MHD connection to handle - * @param tps signed request to execute - * @param merchant_pub public key from the merchant - * @param merchant_sig signature from the merchant (to be checked) - * @param transaction_id transaction ID (in host byte order) - * @return MHD result code - */ -static int -check_and_handle_deposit_wtid_request (struct MHD_Connection *connection, - const struct TALER_DepositTrackPS *tps, - struct TALER_MerchantPublicKeyP *merchant_pub, - struct TALER_MerchantSignatureP *merchant_sig, - uint64_t transaction_id) -{ - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID, - &tps->purpose, - &merchant_sig->eddsa_sig, - &merchant_pub->eddsa_pub)) - { - GNUNET_break_op (0); - return TMH_RESPONSE_reply_signature_invalid (connection, - "merchant_sig"); - } - return TMH_DB_execute_deposit_wtid (connection, - &tps->h_contract, - &tps->h_wire, - &tps->coin_pub, - merchant_pub, - transaction_id); -} - - -/** - * Handle a "/deposit/wtid" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - int res; - json_t *json; - struct TALER_DepositTrackPS tps; - uint64_t transaction_id; - struct TALER_MerchantSignatureP merchant_sig; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("H_wire", &tps.h_wire), - TMH_PARSE_member_fixed ("H_contract", &tps.h_contract), - TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub), - TMH_PARSE_member_uint64 ("transaction_id", &transaction_id), - TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant), - TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - if (GNUNET_OK != res) - { - json_decref (json); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS)); - tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID); - tps.transaction_id = GNUNET_htonll (transaction_id); - res = check_and_handle_deposit_wtid_request (connection, - &tps, - &tps.merchant, - &merchant_sig, - transaction_id); - TMH_PARSE_release_data (spec); - json_decref (json); - return res; -} - - -/* end of taler-mint-httpd_tracking.c */ diff --git a/src/mint/taler-mint-httpd_tracking.h b/src/mint/taler-mint-httpd_tracking.h deleted file mode 100644 index 9ec4c6827..000000000 --- a/src/mint/taler-mint-httpd_tracking.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_tracking.h - * @brief Handle wire transfer tracking-related requests - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_TRACKING_H -#define TALER_MINT_HTTPD_TRACKING_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/wire/deposits" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/deposit/wtid" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/mint/taler-mint-httpd_validation.c b/src/mint/taler-mint-httpd_validation.c deleted file mode 100644 index 8f8ab415e..000000000 --- a/src/mint/taler-mint-httpd_validation.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_validation.c - * @brief helpers for calling the wire plugins to validate addresses - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler-mint-httpd_validation.h" -#include "taler_wire_plugin.h" - - -/** - * Information we keep for each plugin. - */ -struct Plugin -{ - - /** - * We keep plugins in a DLL. - */ - struct Plugin *next; - - /** - * We keep plugins in a DLL. - */ - struct Plugin *prev; - - /** - * Type of the wireformat. - */ - char *type; - - /** - * Pointer to the plugin. - */ - struct TALER_WIRE_Plugin *plugin; - -}; - -/** - * Head of DLL of wire plugins. - */ -static struct Plugin *wire_head; - -/** - * Tail of DLL of wire plugins. - */ -static struct Plugin *wire_tail; - - -/** - * Initialize validation subsystem. - * - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -int -TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct Plugin *p; - char *wireformats; - char *lib_name; - const char *token; - - /* Find out list of supported wire formats */ - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "wireformat", - &wireformats)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "wireformat"); - return GNUNET_SYSERR; - } - for (token = strtok (wireformats, - " "); - NULL != token; - token = strtok (NULL, - " ")) - { - (void) GNUNET_asprintf (&lib_name, - "libtaler_plugin_wire_%s", - token); - p = GNUNET_new (struct Plugin); - p->type = GNUNET_strdup (token); - p->plugin = GNUNET_PLUGIN_load (lib_name, - (void *) cfg); - if (NULL == p->plugin) - { - GNUNET_free (p); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to load plugin %s\n", - lib_name); - GNUNET_free (lib_name); - TMH_VALIDATION_done (); - return GNUNET_SYSERR; - } - p->plugin->library_name = lib_name; - GNUNET_CONTAINER_DLL_insert (wire_head, - wire_tail, - p); - } - GNUNET_free (wireformats); - return GNUNET_OK; -} - - -/** - * Shutdown validation subsystem. - */ -void -TMH_VALIDATION_done () -{ - struct Plugin *p; - char *lib_name; - - while (NULL != (p = wire_head)) - { - GNUNET_CONTAINER_DLL_remove (wire_head, - wire_tail, - p); - lib_name = p->plugin->library_name; - GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, - p->plugin)); - GNUNET_free (lib_name); - GNUNET_free (p->type); - GNUNET_free (p); - } -} - - -/** - * Check if the given wire format JSON object is correctly formatted as - * a wire address. - * - * @param wire the JSON wire format object - * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not - */ -int -TMH_json_validate_wireformat (const json_t *wire) -{ - const char *stype; - json_error_t error; - struct Plugin *p; - - if (0 != json_unpack_ex ((json_t *) wire, - &error, 0, - "{s:s}", - "type", &stype)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - for (p=wire_head; NULL != p; p = p->next) - if (0 == strcasecmp (p->type, - stype)) - return p->plugin->wire_validate (wire); - return GNUNET_NO; -} - - -/** - * Check if we support the given wire method. - * - * @param type type of wire method to check - * @return #GNUNET_YES if the method is supported - */ -int -TMH_VALIDATION_test_method (const char *type) -{ - struct Plugin *p; - - for (p=wire_head;NULL != p;p = p->next) - if (0 == strcasecmp (type, - p->type)) - return GNUNET_YES; - return GNUNET_NO; -} - - -/** - * Obtain supported validation methods as a JSON array, - * and as a hash. - * - * @param[out] h set to the hash of the JSON methods - * @return JSON array with the supported validation methods - */ -json_t * -TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h) -{ - json_t *methods; - struct GNUNET_HashContext *hc; - const char *wf; - struct Plugin *p; - - methods = json_array (); - hc = GNUNET_CRYPTO_hash_context_start (); - for (p=wire_head;NULL != p;p = p->next) - { - wf = p->type; - json_array_append_new (methods, - json_string (wf)); - GNUNET_CRYPTO_hash_context_read (hc, - wf, - strlen (wf) + 1); - } - GNUNET_CRYPTO_hash_context_finish (hc, - h); - return methods; -} - - -/* end of taler-mint-httpd_validation.c */ diff --git a/src/mint/taler-mint-httpd_validation.h b/src/mint/taler-mint-httpd_validation.h deleted file mode 100644 index f5fb19003..000000000 --- a/src/mint/taler-mint-httpd_validation.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_validation.h - * @brief helpers for calling the wire plugins to validate addresses - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_VALIDATION_H -#define TALER_MINT_HTTPD_VALIDATION_H -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> - - -/** - * Initialize validation subsystem. - * - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -int -TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Shutdown validation subsystem. - */ -void -TMH_VALIDATION_done (void); - - -/** - * Check if the given wire format JSON object is correctly formatted as - * a wire address. - * - * @param wire the JSON wire format object - * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not - */ -int -TMH_json_validate_wireformat (const json_t *wire); - -/** - * Check if we support the given wire method. - * - * @param type type of wire method to check - * @return #GNUNET_YES if the method is supported - */ -int -TMH_VALIDATION_test_method (const char *type); - - -/** - * Obtain supported validation methods as a JSON array, - * and as a hash. - * - * @param[out] h set to the hash of the JSON methods - * @return JSON array with the supported validation methods - */ -json_t * -TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h); - - -#endif diff --git a/src/mint/taler-mint-httpd_wire.c b/src/mint/taler-mint-httpd_wire.c deleted file mode 100644 index 020a7e108..000000000 --- a/src/mint/taler-mint-httpd_wire.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_wire.c - * @brief Handle /wire requests - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler-mint-httpd_keystate.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_validation.h" -#include "taler-mint-httpd_wire.h" -#include <jansson.h> - -/** - * Handle a "/wire" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_MintWireSupportMethodsPS wsm; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - json_t *methods; - - wsm.purpose.size = htonl (sizeof (wsm)); - wsm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES); - methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types); - TMH_KS_sign (&wsm.purpose, - &pub, - &sig); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o}", - "methods", methods, - "sig", TALER_json_from_data (&sig, - sizeof (sig)), - "pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * Handle a "/wire/test" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct MHD_Response *response; - int ret; - char *wire_test_redirect; - - response = MHD_create_response_from_buffer (0, NULL, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - if (GNUNET_NO == TMH_VALIDATION_test_method ("test")) - { - /* Return 501: not implemented */ - ret = MHD_queue_response (connection, - MHD_HTTP_NOT_IMPLEMENTED, - response); - MHD_destroy_response (response); - return ret; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint-wire-test", - "REDIRECT_URL", - &wire_test_redirect)) - { - /* oopsie, configuration error */ - MHD_destroy_response (response); - return TMH_RESPONSE_reply_internal_error (connection, - "REDIRECT_URL not configured"); - } - MHD_add_response_header (response, - MHD_HTTP_HEADER_LOCATION, - wire_test_redirect); - GNUNET_free (wire_test_redirect); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Handle a "/wire/sepa" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct MHD_Response *response; - int ret; - char *sepa_wire_file; - int fd; - struct stat sbuf; - - if (GNUNET_NO == TMH_VALIDATION_test_method ("sepa")) - { - /* Return 501: not implemented */ - response = MHD_create_response_from_buffer (0, NULL, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - ret = MHD_queue_response (connection, - MHD_HTTP_NOT_IMPLEMENTED, - response); - MHD_destroy_response (response); - return ret; - } - /* Fetch reply */ - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "mint-wire-sepa", - "SEPA_RESPONSE_FILE", - &sepa_wire_file)) - { - return TMH_RESPONSE_reply_internal_error (connection, - "SEPA_RESPONSE_FILE not configured"); - } - fd = open (sepa_wire_file, - O_RDONLY); - if (-1 == fd) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "open", - sepa_wire_file); - GNUNET_free (sepa_wire_file); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to open SEPA_RESPONSE_FILE"); - } - if (0 != fstat (fd, &sbuf)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "fstat", - sepa_wire_file); - (void) close (fd); - GNUNET_free (sepa_wire_file); - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to open SEPA_RESPONSE_FILE"); - } - response = MHD_create_response_from_fd ((size_t) sbuf.st_size, - fd); - GNUNET_free (sepa_wire_file); - if (NULL == response) - { - (void) close (fd); - GNUNET_break (0); - return MHD_NO; - } - TMH_RESPONSE_add_global_headers (response); - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - -/* end of taler-mint-httpd_wire.c */ diff --git a/src/mint/taler-mint-httpd_wire.h b/src/mint/taler-mint-httpd_wire.h deleted file mode 100644 index e77daf019..000000000 --- a/src/mint/taler-mint-httpd_wire.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_wire.h - * @brief Handle /wire requests - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_WIRE_H -#define TALER_MINT_HTTPD_WIRE_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/wire" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/wire/test" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/wire/sepa" request. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/mint/test_taler_mint_httpd.data b/src/mint/test_taler_mint_httpd.data deleted file mode 100644 index 2d6020355..000000000 --- a/src/mint/test_taler_mint_httpd.data +++ /dev/null @@ -1,48 +0,0 @@ -# This file is part of TALER -# Copyright (C) 2015 GNUnet e.V. -# -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free Software -# Foundation; either version 3, or (at your option) any later version. -# -# TALER is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along with -# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -# -# -# This is a resource file for test_taler_mint_httpd.sh. -# Lines starting with '#' (must be first character in line) are comments. -# -# Each non-comment line must contain two strings, the first being the -# URL on the HTTP serve which a HTTP POST request should be made out -# two, followed by the JSON data to POST to the server. -# -# Note that neither element may contain any spaces! -# -# -# Bad amount: -/admin/add/incoming {"reserve_pub":"7RZBZ86677QMASD2KAYGEPD246C7B7RC6P101FNTG6ZK8X61A620","amount":"1","execution_date":"\/Date(1435934428788)\/","wire":{"empty":"empty"}} -# -# Bad wire format: -/admin/add/incoming {"reserve_pub":"6VRFYZRVHJ434BV3J018MS6H7Q1V5Q6YECNMEF9G4WKB8QJQCAX0","amount":{"currency":"EUR","value":10,"fraction":3},"execution_date":"\/Date(1436258333286)\/","wire":{"empty":"empty"}} -# -# Malformed JSON (ill-balanced quotes around 'amount') -/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0",amount":{"currency":"EUR","value":5,"fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}} -# -# Bad amount (value not a string) -/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":{"currency":"EUR","value":"5","fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}} -# -# Bad amount (overall amount is a string) -/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":"{\"currency\":\"EUR\",\"value\":5,\"fraction\":3}","execution_date":"\/Date(1436271156447)\/","wire":{"type":"test"}} -# -# Bogus denomination key -/deposit {"f":{"currency":"EUR","value":5,"fraction":0},"H_contract":"NRT9E07FYT147V4VCDG0102P0YX0FZ11ZRG90F4X1HDV95M0J64ZVE4XQGNN9MJ3B5K3JX6TJ181KNGRYSZSTYZ5PQHBM1F9QKQ5B50","wire":{"bank":"dest bank","type":"TEST","account":42},"timestamp":"/Date(1436823947)/","coin_pub":"2KCPBGZ77VGJT4DG99EZAY0GQ5TJ89DF53FWYR5RFRTK0CCXRMFG","denom_pub":"51B7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_sig":"W1TDFCSW5XQX9ZF4QPVP3JAJFYA7G4X6SY2B49KRNTDMA685M9YNFETV4610RFKZMSQ3RBRCYBJQH1ZQSMTDMW9W8X6C9SGPCA5ST0R","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DSQ8913AC1S7513EC9G6914AE228H236HHR68VKCCSK650MAGSM6GV3GCHP6D330H1R8GVKJD9P68W46H9Q8GVK8HA6752M2CSN8N248DHJ8H346E9J8RS4CDA28D33ECJ38S33JC9R6MRM8D9G74WM8HA668T44H1N6RT44GHS8CSK8H1G6D346C9J6CS3EC1N8H2M4HA38CSK2D246CW4CD1P70VMAD1Q891K8H1M64TK6C258MRM6G9R88RM6E2488WK2CSQ6GW3GH9N64RKGH2375136GA66533GCSJ65344CHH84W38HHP75330DA58RSKJCJ364SK0C1R8GVK6DSP61134HA48GT4CE1J6MW36C9G891K2GT68GTMCCSQ890M8E1P88R44DA174VK4E135452081918G2J2G0","transaction_id":1,"merchant_pub":"4032W2ZXFW000KRJQDH3CZR00000000004000030P6YG1NR50000","refund_deadline":"/Date(0)/"} -# -# missing coin_ev argument -/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","#oin_ev":"7DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"} -# -# malformed coin_ev argument -/withdraw/sign {"denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_ev":"'DPN42W14BWWD2NWNDYP086276CFV0H8VEV43NFWQGZ3Y8WVR5R5HCN8THX43Z61TFN3CH9N6X5Q0P0T9NF2G8ZWBH8KXEQFQ973CMDDHF1FSE2G9289AB9ERHM8X222VB2WS733X36P8EMG4D3T1N2JHFP530C9RPEAPHDQXZABB6CJ63YD0581JVRY365HHF20RW3BNVKXP","reserve_sig":"VPKYWKGE6FB172XX222N1J0TAEXQE6VERN5X4ANJ0D9K1E7JAX01CPR1PT51SKK5JD72H1GRJ0S2ZQSKN22ZBEGKS77GMT6BF6DD030","reserve_pub":"FN7ARB2MJH2EDMMVT2985Y141YTCE503FS27BTNQ6JSCG3GMBJDG"} diff --git a/src/mint/test_taler_mint_httpd.sh b/src/mint/test_taler_mint_httpd.sh deleted file mode 100755 index 05d26620b..000000000 --- a/src/mint/test_taler_mint_httpd.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# This file is part of TALER -# Copyright (C) 2015 GNUnet e.V. -# -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free Software -# Foundation; either version 3, or (at your option) any later version. -# -# TALER is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along with -# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -# -# -# This script uses 'curl' to POST various ill-formed requests to the -# taler-mint-httpd. Basically, the goal is to make sure that the -# HTTP server survives (and produces the 'correct' error code). -# -# We read the JSON snippets to POST from test_taler_mint_httpd.data -# -# Setup keys. -taler-mint-keyup -d test-mint-home -m test-mint-home/master.priv -# Run Mint HTTPD (in background) -taler-mint-httpd -d test-mint-home & -# Give HTTP time to start -sleep 2 -# Run test... -cat test_taler_mint_httpd.data | grep -v ^\# | awk '{ print "curl -d '\''" $2 "'\'' http://localhost:8081"$1 }' | bash -# Stop HTTP server -kill -TERM %% -# FIXME: not sure this is the 'correct' return code... -exit $? diff --git a/src/mint/test_taler_mint_httpd_afl.sh b/src/mint/test_taler_mint_httpd_afl.sh deleted file mode 100755 index d2c40c216..000000000 --- a/src/mint/test_taler_mint_httpd_afl.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# -# This file is part of TALER -# Copyright (C) 2015 GNUnet e.V. -# -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free Software -# Foundation; either version 3, or (at your option) any later version. -# -# TALER is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along with -# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -# -# -# This script uses 'curl' to POST various ill-formed requests to the -# taler-mint-httpd. Basically, the goal is to make sure that the -# HTTP server survives (and produces the 'correct' error code). -# -# We read the JSON snippets from afl-tests/ -# -PREFIX= -# Uncomment this line to run with valgrind... -PREFIX="valgrind --leak-check=yes --log-file=valgrind.%p" -# Setup keys. -taler-mint-keyup -d test-mint-home -m test-mint-home/master.priv -# Setup database (just to be sure) -taler-mint-dbinit -d test-mint-home &> /dev/null || true -# Only log hard errors, we expect lots of warnings... -export GNUNET_FORCE_LOG="taler-mint-httpd;;;;ERROR/libmicrohttpd;;;;ERROR/util;;;;ERROR/" -# Run test... -for n in afl-tests/* -do - echo -n "Test $n " - $PREFIX taler-mint-httpd -d test-mint-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; } -# $PREFIX taler-mint-httpd -d test-mint-home/ -t 1 -f $n -C > /dev/null || { echo "FAIL!"; exit 1; } - echo "OK" -done -exit 0 diff --git a/src/mintdb/Makefile.am b/src/mintdb/Makefile.am deleted file mode 100644 index e3d37b2e5..000000000 --- a/src/mintdb/Makefile.am +++ /dev/null @@ -1,110 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS) - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -plugindir = $(libdir)/taler - -if HAVE_POSTGRESQL -plugin_LTLIBRARIES = \ - libtaler_plugin_mintdb_postgres.la -endif - -EXTRA_DIST = \ - plugin_mintdb_common.c \ - test-mint-db-postgres.conf - -libtaler_plugin_mintdb_postgres_la_SOURCES = \ - plugin_mintdb_postgres.c -libtaler_plugin_mintdb_postgres_la_LIBADD = \ - $(LTLIBINTL) -libtaler_plugin_mintdb_postgres_la_LDFLAGS = \ - $(TALER_PLUGIN_LDFLAGS) \ - $(top_builddir)/src/pq/libtalerpq.la \ - $(top_builddir)/src/util/libtalerutil.la \ - -lpq \ - -lgnunetpq \ - -lgnunetutil $(XLIB) - -lib_LTLIBRARIES = \ - libtalermintdb.la - -libtalermintdb_la_SOURCES = \ - mintdb_keyio.c \ - mintdb_plugin.c - -libtalermintdb_la_LIBADD = \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetutil $(XLIB) - -libtalermintdb_la_LDFLAGS = \ - $(POSTGRESQL_LDFLAGS) \ - -version-info 0:0:0 \ - -no-undefined - - -check_PROGRAMS = \ - test-mintdb-deposits \ - test-mintdb-keyio \ - test-mintdb-postgres \ - test-perf-taler-mintdb \ - perf-mintdb - -TESTS = \ - test-mintdb-postgres \ - test-perf-taler-mintdb - -test_mintdb_deposits_SOURCES = \ - test_mintdb_deposits.c -test_mintdb_deposits_LDADD = \ - libtalermintdb.la \ - $(top_srcdir)/src/util/libtalerutil.la \ - $(top_srcdir)/src/pq/libtalerpq.la \ - -lgnunetutil \ - -ljansson \ - -lpq - -test_mintdb_keyio_SOURCES = \ - test_mintdb_keyio.c -test_mintdb_keyio_LDADD = \ - libtalermintdb.la \ - $(top_srcdir)/src/util/libtalerutil.la \ - $(top_srcdir)/src/pq/libtalerpq.la \ - -lgnunetutil - -test_mintdb_postgres_SOURCES = \ - test_mintdb.c -test_mintdb_postgres_LDADD = \ - libtalermintdb.la \ - $(top_srcdir)/src/util/libtalerutil.la \ - $(top_srcdir)/src/pq/libtalerpq.la \ - -lgnunetutil -ljansson - -test_perf_taler_mintdb_SOURCES = \ - test_perf_taler_mintdb.c \ - perf_taler_mintdb_init.c \ - perf_taler_mintdb_interpreter.c -test_perf_taler_mintdb_LDADD = \ - libtalermintdb.la \ - $(top_srcdir)/src/util/libtalerutil.la \ - $(top_srcdir)/src/pq/libtalerpq.la \ - -ljansson \ - -lgnunetutil - -perf_mintdb_SOURCES = \ - perf_taler_mintdb.c \ - perf_taler_mintdb_init.c \ - perf_taler_mintdb_interpreter.c -perf_mintdb_LDADD = \ - libtalermintdb.la \ - $(top_srcdir)/src/util/libtalerutil.la \ - $(top_srcdir)/src/pq/libtalerpq.la \ - -ljansson \ - -lgnunetutil - - -EXTRA_test_mintdb_postgres_DEPENDENCIES = \ - libtaler_plugin_mintdb_postgres.la diff --git a/src/mintdb/mintdb_keyio.c b/src/mintdb/mintdb_keyio.c deleted file mode 100644 index 89ac9055a..000000000 --- a/src/mintdb/mintdb_keyio.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mintdb/mintdb_keyio.c - * @brief I/O operations for the Mint's private keys - * @author Florian Dold - * @author Benedikt Mueller - * @author Sree Harsha Totakura - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_mintdb_lib.h" - - -/** - * Closure for the #signkeys_iterate_dir_iter(). - */ -struct SignkeysIterateContext -{ - - /** - * Function to call on each signing key. - */ - TALER_MINTDB_SigningKeyIterator it; - - /** - * Closure for @e it. - */ - void *it_cls; -}; - - -/** - * Function called on each file in the directory with our signing - * keys. Parses the file and calls the iterator from @a cls. - * - * @param cls the `struct SignkeysIterateContext *` - * @param filename name of the file to parse - * @return #GNUNET_OK to continue, - * #GNUNET_NO to stop iteration without error, - * #GNUNET_SYSERR to stop iteration with error - */ -static int -signkeys_iterate_dir_iter (void *cls, - const char *filename) -{ - struct SignkeysIterateContext *skc = cls; - ssize_t nread; - struct TALER_MINTDB_PrivateSigningKeyInformationP issue; - - nread = GNUNET_DISK_fn_read (filename, - &issue, - sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP)); - if (nread != sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid signkey file `%s': wrong size (%d, expected %u)\n", - filename, - (int) nread, - sizeof (struct TALER_MINTDB_PrivateSigningKeyInformationP)); - return GNUNET_OK; - } - return skc->it (skc->it_cls, - filename, - &issue); -} - - -/** - * Call @a it for each signing key found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_SIGNING_KEYS - * subdirectory - * @param it function to call on each signing key - * @param it_cls closure for @a it - * @return number of files found (may not match - * number of keys given to @a it as malformed - * files are simply skipped), -1 on error - */ -int -TALER_MINTDB_signing_keys_iterate (const char *mint_base_dir, - TALER_MINTDB_SigningKeyIterator it, - void *it_cls) -{ - char *signkey_dir; - struct SignkeysIterateContext skc; - int ret; - - GNUNET_asprintf (&signkey_dir, - "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_SIGNING_KEYS, - mint_base_dir); - skc.it = it; - skc.it_cls = it_cls; - ret = GNUNET_DISK_directory_scan (signkey_dir, - &signkeys_iterate_dir_iter, - &skc); - GNUNET_free (signkey_dir); - return ret; -} - - -/** - * Import a denomination key from the given file. - * - * @param filename the file to import the key from - * @param[out] dki set to the imported denomination key - * @return #GNUNET_OK upon success; - * #GNUNET_SYSERR upon failure - */ -int -TALER_MINTDB_denomination_key_read (const char *filename, - struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - uint64_t size; - size_t offset; - void *data; - struct GNUNET_CRYPTO_rsa_PrivateKey *priv; - - if (GNUNET_OK != GNUNET_DISK_file_size (filename, - &size, - GNUNET_YES, - GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping inaccessable denomination key file `%s'\n", - filename); - return GNUNET_SYSERR; - } - offset = sizeof (struct TALER_MINTDB_DenominationKeyInformationP); - if (size <= offset) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - data = GNUNET_malloc (size); - if (size != - GNUNET_DISK_fn_read (filename, - data, - size)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "read", - filename); - GNUNET_free (data); - return GNUNET_SYSERR; - } - if (NULL == - (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset, - size - offset))) - { - GNUNET_free (data); - return GNUNET_SYSERR; - } - GNUNET_assert (NULL == dki->denom_priv.rsa_private_key); - dki->denom_priv.rsa_private_key = priv; - dki->denom_pub.rsa_public_key - = GNUNET_CRYPTO_rsa_private_key_get_public (priv); - memcpy (&dki->issue, - data, - offset); - GNUNET_free (data); - return GNUNET_OK; -} - - -/** - * Exports a denomination key to the given file. - * - * @param filename the file where to write the denomination key - * @param dki the denomination key - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. - */ -int -TALER_MINTDB_denomination_key_write (const char *filename, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - char *priv_enc; - size_t priv_enc_size; - struct GNUNET_DISK_FileHandle *fh; - ssize_t wrote; - size_t wsize; - int ret; - - fh = NULL; - priv_enc_size - = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key, - &priv_enc); - ret = GNUNET_SYSERR; - if (NULL == (fh = GNUNET_DISK_file_open - (filename, - GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, - GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) - goto cleanup; - wsize = sizeof (struct TALER_MINTDB_DenominationKeyInformationP); - if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, - &dki->issue, - wsize))) - goto cleanup; - if (wrote != wsize) - goto cleanup; - if (GNUNET_SYSERR == - (wrote = GNUNET_DISK_file_write (fh, - priv_enc, - priv_enc_size))) - goto cleanup; - if (wrote != priv_enc_size) - goto cleanup; - ret = GNUNET_OK; - cleanup: - GNUNET_free_non_null (priv_enc); - if (NULL != fh) - (void) GNUNET_DISK_file_close (fh); - return ret; -} - - -/** - * Closure for #denomkeys_iterate_keydir_iter() and - * #denomkeys_iterate_topdir_iter(). - */ -struct DenomkeysIterateContext -{ - - /** - * Set to the name of the directory below the top-level directory - * during the call to #denomkeys_iterate_keydir_iter(). - */ - const char *alias; - - /** - * Function to call on each denomination key. - */ - TALER_MINTDB_DenominationKeyIterator it; - - /** - * Closure for @e it. - */ - void *it_cls; -}; - - -/** - * Decode the denomination key in the given file @a filename and call - * the callback in @a cls with the information. - * - * @param cls the `struct DenomkeysIterateContext *` - * @param filename name of a file that should contain - * a denomination key - * @return #GNUNET_OK to continue to iterate - * #GNUNET_NO to abort iteration with success - * #GNUNET_SYSERR to abort iteration with failure - */ -static int -denomkeys_iterate_keydir_iter (void *cls, - const char *filename) -{ - struct DenomkeysIterateContext *dic = cls; - struct TALER_MINTDB_DenominationKeyIssueInformation issue; - int ret; - - memset (&issue, 0, sizeof (issue)); - if (GNUNET_OK != - TALER_MINTDB_denomination_key_read (filename, - &issue)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid denomkey file: '%s'\n", - filename); - return GNUNET_OK; - } - ret = dic->it (dic->it_cls, - dic->alias, - &issue); - GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key); - return ret; -} - - -/** - * Function called on each subdirectory in the #TALER_MINTDB_DIR_DENOMINATION_KEYS. Will - * call the #denomkeys_iterate_keydir_iter() on each file in the - * subdirectory. - * - * @param cls the `struct DenomkeysIterateContext *` - * @param filename name of the subdirectory to scan - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR if we need to abort - */ -static int -denomkeys_iterate_topdir_iter (void *cls, - const char *filename) -{ - struct DenomkeysIterateContext *dic = cls; - - dic->alias = GNUNET_STRINGS_get_short_name (filename); - if (0 > GNUNET_DISK_directory_scan (filename, - &denomkeys_iterate_keydir_iter, - dic)) - return GNUNET_SYSERR; - return GNUNET_OK; -} - - -/** - * Call @a it for each denomination key found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS - * subdirectory - * @param it function to call on each denomination key found - * @param it_cls closure for @a it - * @return -1 on error, 0 if no files were found, otherwise - * a positive number (however, even with a positive - * number it is possible that @a it was never called - * as maybe none of the files were well-formed) - */ -int -TALER_MINTDB_denomination_keys_iterate (const char *mint_base_dir, - TALER_MINTDB_DenominationKeyIterator it, - void *it_cls) -{ - char *dir; - struct DenomkeysIterateContext dic; - int ret; - - GNUNET_asprintf (&dir, - "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_DENOMINATION_KEYS, - mint_base_dir); - dic.it = it; - dic.it_cls = it_cls; - ret = GNUNET_DISK_directory_scan (dir, - &denomkeys_iterate_topdir_iter, - &dic); - GNUNET_free (dir); - return ret; -} - - -/** - * Closure for #auditor_iter() and - */ -struct AuditorIterateContext -{ - - /** - * Function to call with the information for each auditor. - */ - TALER_MINTDB_AuditorIterator it; - - /** - * Closure for @e it. - */ - void *it_cls; -}; - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Header of a file with auditing information. - */ -struct AuditorFileHeaderP -{ - - /** - * Public key of the auditor. - */ - struct TALER_AuditorPublicKeyP apub; - - /** - * Master public key of the mint the auditor is signing - * information for. - */ - struct TALER_MasterPublicKeyP mpub; - -}; -GNUNET_NETWORK_STRUCT_END - - -/** - * Load the auditor signature and the information signed by the - * auditor and call the callback in @a cls with the information. - * - * @param cls the `struct AuditorIterateContext *` - * @param filename name of a file that should contain - * a denomination key - * @return #GNUNET_OK to continue to iterate - * #GNUNET_NO to abort iteration with success - * #GNUNET_SYSERR to abort iteration with failure - */ -static int -auditor_iter (void *cls, - const char *filename) -{ - struct AuditorIterateContext *aic = cls; - uint64_t size; - struct AuditorFileHeaderP *af; - const struct TALER_AuditorSignatureP *sigs; - const struct TALER_DenominationKeyValidityPS *dki; - unsigned int len; - int ret; - - if (GNUNET_OK != GNUNET_DISK_file_size (filename, - &size, - GNUNET_YES, - GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping inaccessable auditor information file `%s'\n", - filename); - return GNUNET_SYSERR; - } - if ( (size < sizeof (struct AuditorFileHeaderP)) || - (0 != (len = ((size - sizeof (struct AuditorFileHeaderP)) % - (sizeof (struct TALER_DenominationKeyValidityPS) + - sizeof (struct TALER_AuditorSignatureP))))) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - af = GNUNET_malloc (size); - if (size != - GNUNET_DISK_fn_read (filename, - af, - size)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "read", - filename); - GNUNET_free (af); - return GNUNET_SYSERR; - } - sigs = (const struct TALER_AuditorSignatureP *) &af[1]; - dki = (const struct TALER_DenominationKeyValidityPS *) &sigs[len]; - ret = aic->it (aic->it_cls, - &af->apub, - &af->mpub, - len, - sigs, - dki); - GNUNET_free (af); - return ret; -} - - -/** - * Call @a it with information for each auditor found in the @a mint_base_dir. - * - * @param mint_base_dir base directory for the mint, - * the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS - * subdirectory - * @param it function to call with auditor information - * @param it_cls closure for @a it - * @return -1 on error, 0 if no files were found, otherwise - * a positive number (however, even with a positive - * number it is possible that @a it was never called - * as maybe none of the files were well-formed) - */ -int -TALER_MINTDB_auditor_iterate (const char *mint_base_dir, - TALER_MINTDB_AuditorIterator it, - void *it_cls) -{ - char *dir; - struct AuditorIterateContext aic; - int ret; - - GNUNET_asprintf (&dir, - "%s" DIR_SEPARATOR_STR TALER_MINTDB_DIR_AUDITORS, - mint_base_dir); - aic.it = it; - aic.it_cls = it_cls; - ret = GNUNET_DISK_directory_scan (dir, - &auditor_iter, - &aic); - GNUNET_free (dir); - return ret; -} - - -/** - * Write auditor information to the given file. - * - * @param filename the file where to write the auditor information to - * @param apub the auditor's public key - * @param asigs the auditor's signatures, array of length @a dki_len - * @param mpub the mint's public key (as expected by the auditor) - * @param dki_len length of @a dki - * @param dki array of denomination coin data signed by the auditor - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. - */ -int -TALER_MINTDB_auditor_write (const char *filename, - const struct TALER_AuditorPublicKeyP *apub, - const struct TALER_AuditorSignatureP *asigs, - const struct TALER_MasterPublicKeyP *mpub, - unsigned int dki_len, - const struct TALER_DenominationKeyValidityPS *dki) -{ - struct AuditorFileHeaderP af; - struct GNUNET_DISK_FileHandle *fh; - ssize_t wrote; - size_t wsize; - int ret; - int eno; - - af.apub = *apub; - af.mpub = *mpub; - ret = GNUNET_SYSERR; - if (NULL == (fh = GNUNET_DISK_file_open - (filename, - GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, - GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) - goto cleanup; - wsize = sizeof (struct AuditorFileHeaderP); - if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, - &af, - wsize))) - goto cleanup; - if (wrote != wsize) - goto cleanup; - wsize = dki_len * sizeof (struct TALER_AuditorSignatureP); - if (wsize == - GNUNET_DISK_file_write (fh, - asigs, - wsize)) - ret = GNUNET_OK; - wsize = dki_len * sizeof (struct TALER_DenominationKeyValidityPS); - if (wsize == - GNUNET_DISK_file_write (fh, - dki, - wsize)) - ret = GNUNET_OK; - cleanup: - eno = errno; - if (NULL != fh) - (void) GNUNET_DISK_file_close (fh); - errno = eno; - return ret; -} - - -/* end of mintdb_keyio.c */ diff --git a/src/mintdb/mintdb_plugin.c b/src/mintdb/mintdb_plugin.c deleted file mode 100644 index 4a0f1dc04..000000000 --- a/src/mintdb/mintdb_plugin.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mintdb/mintdb_plugin.c - * @brief Logic to load database plugin - * @author Christian Grothoff - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ -#include "platform.h" -#include "taler_mintdb_plugin.h" -#include <ltdl.h> - - -/** - * Initialize the plugin. - * - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -struct TALER_MINTDB_Plugin * -TALER_MINTDB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - char *plugin_name; - char *lib_name; - struct GNUNET_CONFIGURATION_Handle *cfg_dup; - struct TALER_MINTDB_Plugin *plugin; - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", - "db", - &plugin_name)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", - "db"); - return NULL; - } - (void) GNUNET_asprintf (&lib_name, - "libtaler_plugin_mintdb_%s", - plugin_name); - GNUNET_free (plugin_name); - cfg_dup = GNUNET_CONFIGURATION_dup (cfg); - plugin = GNUNET_PLUGIN_load (lib_name, cfg_dup); - if (NULL != plugin) - plugin->library_name = lib_name; - else - GNUNET_free (lib_name); - GNUNET_CONFIGURATION_destroy (cfg_dup); - return plugin; -} - - -/** - * Shutdown the plugin. - * - * @param plugin the plugin to unload - */ -void -TALER_MINTDB_plugin_unload (struct TALER_MINTDB_Plugin *plugin) -{ - char *lib_name; - - if (NULL == plugin) - return; - lib_name = plugin->library_name; - GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, - plugin)); - GNUNET_free (lib_name); -} - - - -/* end of mintdb_plugin.c */ diff --git a/src/mintdb/perf_taler_mintdb.c b/src/mintdb/perf_taler_mintdb.c deleted file mode 100644 index fbaa2ce34..000000000 --- a/src/mintdb/perf_taler_mintdb.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/perf_taler_mintdb.c - * @brief Mint database performance analysis - * @author Nicolas Fournier - */ -#include "platform.h" -#include "perf_taler_mintdb_interpreter.h" - - -#define NB_DENOMINATION_INIT 15 -#define NB_DENOMINATION_SAVE 15 - -#define SMALL 1000 -#define BIG 10000 -#define BIGGER 100000 - -#define NB_RESERVE_INIT BIGGER -#define NB_RESERVE_SAVE BIG - -#define NB_DEPOSIT_INIT BIGGER -#define NB_DEPOSIT_SAVE BIG - -#define NB_WITHDRAW_INIT BIGGER -#define NB_WITHDRAW_SAVE BIG - -#define NB_REFRESH_INIT BIGGER -#define NB_REFRESH_SAVE BIG - -#define NB_MELT_INIT BIG -#define NB_MELT_SAVE SMALL - -/** - * Runs the performances tests for the mint database - * and logs the results using Gauger - */ -int -main (int argc, char ** argv) -{ - int ret; - struct PERF_TALER_MINTDB_Cmd benchmark[] = - { - /* Denomination used to create coins */ - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("Initializing database"), - - PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop", - NB_DENOMINATION_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", - "01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", - "01 - denomination loop", - "01 - denomination", - NB_DENOMINATION_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("01 - end", - "01 - denomination loop"), - /* End of initialization */ - /* Reserve initialization */ - PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop", - NB_RESERVE_INIT), - PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert", - "02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", - "02 - init reserve loop", - "02 - reserve", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("02 - end", - "02 - init reserve loop"), - /* End reserve init */ - /* Withdrawal initialization */ - PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop", - NB_WITHDRAW_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", - "03 - init withdraw loop", - "01 - save denomination"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", - "03 - init withdraw loop", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", - "03 - denomination load", - "03 - reserve load"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert", - "03 - withdraw"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - save coin", - "03 - init withdraw loop", - "03 - withdraw", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("03 - end", - "03 - init withdraw loop"), - /*End of withdrawal initialization */ - /*Deposit initialization */ - PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop", - NB_DEPOSIT_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - coin load", - "04 - deposit init loop", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit", - "04 - coin load"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert", - "04 - deposit"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", - "04 - deposit init loop", - "04 - deposit", - NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "04 - deposit init loop"), - /* End of deposit initialization */ - /* Session initialization */ - PERF_TALER_MINTDB_INIT_CMD_LOOP ("05 - refresh session init loop", - NB_REFRESH_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION ("05 - refresh session"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("05 - session array", - "05 - refresh session init loop", - "05 - refresh session", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("05 - end", - "05 - refresh session init loop"), - /* End of refresh session initialization */ - /* Refresh melt initialization */ - PERF_TALER_MINTDB_INIT_CMD_LOOP ("06 - refresh melt init loop", - NB_MELT_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - /* TODO: initialize using coins & sessions created localy - * in order to make sure the same coin are not melted twice*/ - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("06 - session hash", - "06 - refresh melt init loop", - "05 - session array"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("06 - coin", - "06 - refresh melt init loop", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_REFRESH_MELT ("06 - refresh melt", - "06 - session hash", - "06 - coin"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("06 - end", - "06 - refresh melt init loop"), - /* End of refresh melt initialization */ - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of initialization"), - - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("Start of performances measuring"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("21 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("21 - reserve insert measure", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("21 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("21 - insert", - "21 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "21 - reserve insert measure"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("21 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("21 - gauger", - "21 - start", - "21 - stop", - "POSTGRES", - "Number of reserve inserted per second", - "item/sec", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve insertion"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("22 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("22 - reserve load measure", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("22 - reserve", - "22 - reserve load measure", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE ("22 - get", - "22 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "22 - reserve load measure"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("22 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "22 - start", - "22 - stop", - "POSTGRES", - "Number of reserve loaded per second", - "item/sec", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve retreival"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("23 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("23 - reserve history measure", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("23 - reserve", - "23 - reserve history measure", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY ("", - "23 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "23 - reserve history measure"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("23 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "23 - start", - "23 - stop", - "POSTGRES", - "Number of reserve history loaded per second", - "item/sec", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of reserve history access"), - - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("24 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("24 - withdraw insert measure", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("24 - reserve", - "24 - withdraw insert measure", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("24 - denomination", - "24 - withdraw insert measure", - "01 - save denomination"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("24 - withdraw", - "24 - denomination", - "24 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("24 - insert", - "24 - withdraw"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "24 - withdraw insert measure"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("24 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "24 - start", - "24 - stop", - "POSTGRES", - "Number of withdraw insert per second", - "item/sec", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of withdraw insertion"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("25 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("25 - withdraw insert measure", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("25 - coin", - "25 - withdraw insert measure", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_GET_WITHDRAW ("", - "25 - coin"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "25 - withdraw insert measure"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("25 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "25 - start", - "25 - stop", - "POSTGRES", - "Number of withdraw loaded per second", - "item/sec", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of withdraw loading"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("26 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("26 - get coin transaction", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("26 - coin", - "26 - get coin transaction", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION("", - "26 - coin"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "26 - get coin transaction"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("26 - end"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "26 - start", - "26 - end", - "POSTGRES", - "Number of coin transaction history loaded per second", - "item/sec", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of transaction loading"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("27 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("27 - /reserve/withdraw", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("27 - reserve", - "27 - /reserve/withdraw", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("27 - dki", - "27 - /reserve/withdraw", - "01 - save denomination"), - PERF_TALER_MINTDB_INIT_CMD_WITHDRAW_SIGN ("", - "27 - dki", - "27 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "27 - /reserve/withdraw"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("27 - end"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "27 - start", - "27 - end", - "POSTGRES", - "Number of /reserve/withdraw per second", - "item/sec", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("End of /reserve/withdraw"), - - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("28 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("28 - /deposit", - NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("28 - coin", - "28 - /deposit", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_DEPOSIT ("28 - deposit", - "28 - coin"), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "28 - /deposit"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("28 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "28 - start", - "28 - stop", - "POSTGRES", - "Number of /deposit per second", - "item/sec", - NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("29 - start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("29 - insert refresh session", - NB_REFRESH_SAVE), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION (""), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "29 - insert refresh session"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("29 - stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("", - "29 - start", - "29 - stop", - "POSTGRES", - "Number of refresh session inserted per second", - "item/sec", - NB_REFRESH_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END (""), - }; - - ret = PERF_TALER_MINTDB_run_benchmark ( - "perf-taler-mintdb", - "./test-mint-db-postgres.conf", - (struct PERF_TALER_MINTDB_Cmd []) {PERF_TALER_MINTDB_INIT_CMD_END("")}, - benchmark); - if (GNUNET_SYSERR == ret) - return 1; - return 0; -} diff --git a/src/mintdb/perf_taler_mintdb_init.c b/src/mintdb/perf_taler_mintdb_init.c deleted file mode 100644 index ccfc6a05a..000000000 --- a/src/mintdb/perf_taler_mintdb_init.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/perf_taler_mintdb_init.c - * @brief Interpreter library for mint database performance analysis - * @author Nicolas Fournier - */ -#include "platform.h" -#include "perf_taler_mintdb_init.h" -#include <gnunet/gnunet_signatures.h> -#include "taler_signatures.h" -#include "taler_amount_lib.h" - - -#define CURRENCY "EUR" -#define PERF_TALER_MINTDB_RSA_SIZE 512 - - -/** - * Generate a dummy DenominationKeyInformation for testing purposes - * @return a dummy denomination key - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -PERF_TALER_MINTDB_denomination_init () -{ - struct GNUNET_CRYPTO_EddsaPrivateKey *master_prvt; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_DenominationPrivateKey denom_priv; - struct TALER_DenominationPublicKey denom_pub; - struct TALER_MINTDB_DenominationKeyInformationP issue; - - master_prvt = GNUNET_CRYPTO_eddsa_key_create(); - - dki = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation); - GNUNET_assert (NULL != dki); - denom_priv.rsa_private_key - = GNUNET_CRYPTO_rsa_private_key_create (PERF_TALER_MINTDB_RSA_SIZE); - GNUNET_assert (NULL != denom_priv.rsa_private_key); - denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv.rsa_private_key); - GNUNET_assert (NULL != denom_pub.rsa_public_key); - {/* issue */ - struct TALER_MasterSignatureP signature; - struct TALER_DenominationKeyValidityPS properties; - - {/* properties */ - struct TALER_Amount amount; - - properties.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); - properties.purpose.size = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); - GNUNET_CRYPTO_eddsa_key_get_public (master_prvt, - &properties.master.eddsa_pub); - properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get()); - properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); - properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); - properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_()); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.1", &amount)); - TALER_amount_hton (&properties.value, &amount); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.1", &amount)); - TALER_amount_hton (&properties.fee_withdraw, &amount); - TALER_amount_hton (&properties.fee_deposit, &amount); - TALER_amount_hton (&properties.fee_refresh, &amount); - GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, - &properties.denom_hash); - issue.properties = properties; - } - {/* signature */ - GNUNET_CRYPTO_eddsa_sign (master_prvt, - &properties.purpose, - &signature.eddsa_signature); - issue.signature = signature; - } - } - dki->denom_priv = denom_priv; - dki->denom_pub = denom_pub; - dki->issue = issue; - GNUNET_free (master_prvt); - return dki; -} - - -/** - * Copies the given denomination - * @param reserve the deposit copy - * @return a copy of @a deposit; NULL if error - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -PERF_TALER_MINTDB_denomination_copy (const struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *copy; - - GNUNET_assert (NULL != - (copy = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation))); - {/* denom_priv */ - copy->denom_priv.rsa_private_key = - GNUNET_CRYPTO_rsa_private_key_dup ( dki->denom_priv.rsa_private_key); - } - {/* denom_pub */ - copy->denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); - } - {/* issue */ - copy->issue.properties = dki->issue.properties; - copy->issue.signature = dki->issue.signature; - } - return copy; -} - - -/** - * Free memory of a DenominationKeyIssueInformation - * @param dki pointer to the struct to free - */ -int -PERF_TALER_MINTDB_denomination_free (struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - if (NULL == dki) - return GNUNET_OK; - GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key); - - GNUNET_free (dki); - return GNUNET_OK; -} - - -/** - * Generate a dummy reserve for testing - * @return a reserve with 1000 EUR in it - */ -struct PERF_TALER_MINTDB_Reserve * -PERF_TALER_MINTDB_reserve_init () -{ - struct PERF_TALER_MINTDB_Reserve *reserve; - - GNUNET_assert (NULL != - (reserve = GNUNET_new (struct PERF_TALER_MINTDB_Reserve))); - {/* private */ - struct GNUNET_CRYPTO_EddsaPrivateKey *private; - private = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_assert (NULL != private); - reserve->private = *private; - GNUNET_free (private); - } - - GNUNET_CRYPTO_eddsa_key_get_public (&reserve->private, - &reserve->reserve.pub.eddsa_pub); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1000", &reserve->reserve.balance)); - reserve->reserve.expiry = GNUNET_TIME_absolute_get_forever_ (); - return reserve; -} - - -/** - * Copies the given reserve - * @param reserve the reserve to copy - * @return a copy of @a reserve; NULL if error - */ -struct PERF_TALER_MINTDB_Reserve * -PERF_TALER_MINTDB_reserve_copy (const struct PERF_TALER_MINTDB_Reserve *reserve) -{ - struct PERF_TALER_MINTDB_Reserve *copy; - GNUNET_assert (NULL != - (copy = GNUNET_new (struct PERF_TALER_MINTDB_Reserve))); - *copy = *reserve; - return copy; -} - - -/** - * Free memory of a reserve - * @param reserve pointer to the structure to be freed - */ -int -PERF_TALER_MINTDB_reserve_free (struct PERF_TALER_MINTDB_Reserve *reserve) -{ - if (NULL == reserve) - return GNUNET_OK; - GNUNET_free (reserve); - return GNUNET_OK; -} - - -/** - * Generate a dummy deposit for testing purposes - * @param dki the denomination key used to sign the key - */ -struct TALER_MINTDB_Deposit * -PERF_TALER_MINTDB_deposit_init (const struct PERF_TALER_MINTDB_Coin *coin) -{ - struct TALER_MINTDB_Deposit *deposit; - struct TALER_CoinSpendSignatureP csig; - struct TALER_MerchantPublicKeyP merchant_pub; - struct GNUNET_HashCode h_contract; - struct GNUNET_HashCode h_wire; - const char wire[] = "{" - "\"type\":\"SEPA\"," - "\"IBAN\":\"DE67830654080004822650\"," - "\"NAME\":\"GNUNET E.\"," - "\"BIC\":\"GENODEF1SRL\"" - "}"; - static uint64_t transaction_id = 0; - struct GNUNET_TIME_Absolute timestamp; - struct GNUNET_TIME_Absolute refund_deadline; - struct TALER_Amount amount_with_fee; - struct TALER_Amount deposit_fee; - - GNUNET_assert (NULL != - (deposit = GNUNET_malloc (sizeof (struct TALER_MINTDB_Deposit) + sizeof (wire)))); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &h_contract); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &h_wire); - { //csig - struct u32_presign - { - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_wire; - struct GNUNET_HashCode h_contract; - } unsigned_data; - - unsigned_data.h_contract = h_contract; - unsigned_data.h_wire = h_wire; - unsigned_data.purpose.size = htonl (sizeof (struct u32_presign)); - unsigned_data.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&coin->priv, - &unsigned_data.purpose, - &csig.eddsa_signature)); - } - { //merchant_pub - struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_prv; - - eddsa_prv = GNUNET_CRYPTO_eddsa_key_create (); - GNUNET_assert(NULL != eddsa_prv); - GNUNET_CRYPTO_eddsa_key_get_public ( - eddsa_prv, - &merchant_pub.eddsa_pub); - GNUNET_free (eddsa_prv); - } - timestamp = GNUNET_TIME_absolute_get (); - refund_deadline = GNUNET_TIME_absolute_get (); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.1", - &amount_with_fee)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.1", - &deposit_fee)); - { - deposit->coin.coin_pub = coin->public_info.coin_pub; - deposit->coin.denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup ( - coin->public_info.denom_pub.rsa_public_key); - GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key); - deposit->coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup ( - coin->public_info.denom_sig.rsa_signature); - GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature); - } - deposit->csig = csig; - deposit->h_contract = h_contract; - deposit->h_wire = h_wire; - deposit->wire = json_loads (wire, 0, NULL); - deposit->transaction_id = transaction_id++; - deposit->timestamp = timestamp; - deposit->refund_deadline = refund_deadline; - deposit->amount_with_fee = amount_with_fee; - deposit->deposit_fee = deposit_fee; - return deposit; -} - - -/** - * Copies the given deposit - * @param reserve the deposit copy - * @return a copy of @a deposit; NULL if error - */ -struct TALER_MINTDB_Deposit * -PERF_TALER_MINTDB_deposit_copy (const struct TALER_MINTDB_Deposit *deposit) -{ - struct TALER_MINTDB_Deposit *copy; - - copy = GNUNET_new (struct TALER_MINTDB_Deposit); - *copy = *deposit; - json_incref (copy->wire); - copy->coin.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key); - copy->coin.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (deposit->coin.denom_sig.rsa_signature); - return copy; -} - - -/** - * Free memory of a deposit - * @param deposit pointer to the structure to free - */ -int -PERF_TALER_MINTDB_deposit_free (struct TALER_MINTDB_Deposit *deposit) -{ - if (NULL == deposit) - return GNUNET_OK; - GNUNET_CRYPTO_rsa_public_key_free (deposit->coin.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (deposit->coin.denom_sig.rsa_signature); - json_decref (deposit->wire); - GNUNET_free (deposit); - return GNUNET_OK; -} - - -/** - * Generate a CollectableBlindcoin for testing purpuses - * @param dki denomination key used to sign the coin - * @param reserve reserve providing the money for the coin - * @return a randomly generated CollectableBlindcoin - */ -struct PERF_TALER_MINTDB_Coin * -PERF_TALER_MINTDB_coin_init ( - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki, - const struct PERF_TALER_MINTDB_Reserve *reserve) -{ - struct PERF_TALER_MINTDB_Coin *coin; - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - coin = GNUNET_new (struct PERF_TALER_MINTDB_Coin); - GNUNET_assert (NULL != coin); - /* priv */ - - priv = GNUNET_CRYPTO_eddsa_key_create(); - GNUNET_assert (NULL != priv); - coin->priv = *priv; - GNUNET_free (priv); - - /* public_info */ - GNUNET_CRYPTO_eddsa_key_get_public (&coin->priv, - &coin->public_info.coin_pub.eddsa_pub); - coin->public_info.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); - coin->public_info.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, - &coin->public_info.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key); - GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature); - - /* blind */ - coin->blind.sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); - coin->blind.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); - GNUNET_assert (NULL != coin->blind.sig.rsa_signature); - GNUNET_assert (NULL != coin->blind.denom_pub.rsa_public_key); - TALER_amount_ntoh (&coin->blind.amount_with_fee, - &dki->issue.properties.value); - TALER_amount_ntoh (&coin->blind.withdraw_fee, - &dki->issue.properties.fee_withdraw); - coin->blind.reserve_pub = reserve->reserve.pub; - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &coin->blind.h_coin_envelope); - - return coin; -} - - -/** - * Copies the given coin - * - * @param coin the coin to copy - * @return a copy of coin; NULL if error - */ -struct PERF_TALER_MINTDB_Coin * -PERF_TALER_MINTDB_coin_copy (const struct PERF_TALER_MINTDB_Coin *coin) -{ - struct PERF_TALER_MINTDB_Coin *copy; - - copy = GNUNET_new (struct PERF_TALER_MINTDB_Coin); - /* priv */ - copy->priv = coin->priv; - /* public_info */ - copy->public_info.coin_pub = coin->public_info.coin_pub; - copy->public_info.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key); - copy->public_info.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); - - /* blind */ - copy->blind.sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (coin->blind.sig.rsa_signature); - copy->blind.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (coin->blind.denom_pub.rsa_public_key); - copy->blind.amount_with_fee = coin->blind.amount_with_fee; - copy->blind.withdraw_fee = coin->blind.withdraw_fee; - copy->blind.reserve_pub = coin->blind.reserve_pub; - copy->blind.h_coin_envelope = coin->blind.h_coin_envelope; - copy->blind.reserve_sig = coin->blind.reserve_sig; - - return copy; -} - - -/** - * Free memory of @a coin - * - * @param coin pointer to the structure to free - */ -int -PERF_TALER_MINTDB_coin_free (struct PERF_TALER_MINTDB_Coin *coin) -{ - if (NULL == coin) - return GNUNET_OK; - GNUNET_CRYPTO_rsa_public_key_free (coin->public_info.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (coin->public_info.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_signature_free (coin->blind.sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (coin->blind.denom_pub.rsa_public_key); - GNUNET_free (coin); - return GNUNET_OK; -} - - -/** - * @return a randomly generated refresh session - */ -struct TALER_MINTDB_RefreshSession * -PERF_TALER_MINTDB_refresh_session_init () -{ - struct TALER_MINTDB_RefreshSession *refresh_session; - - GNUNET_assert (NULL != - (refresh_session = GNUNET_new (struct TALER_MINTDB_RefreshSession))); - refresh_session->noreveal_index = 1; - refresh_session->num_oldcoins = 1; - refresh_session->num_newcoins = 1; - - return refresh_session; -} - - -/** - * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't - */ -int -PERF_TALER_MINTDB_refresh_session_copy (struct TALER_MINTDB_RefreshSession *session, - struct TALER_MINTDB_RefreshSession *copy) -{ - *copy = *session; - return GNUNET_OK; -} - - -/** - * Free a refresh session - */ -int -PERF_TALER_MINTDB_refresh_session_free (struct TALER_MINTDB_RefreshSession *refresh_session) -{ - if (NULL == refresh_session) - return GNUNET_OK; - GNUNET_free (refresh_session); - return GNUNET_OK; -} - - -/** - * Create a melt operation - * - * @param session the refresh session - * @param dki the denomination the melted coin uses - * @return a pointer to a #TALER_MINTDB_RefreshMelt - */ -struct TALER_MINTDB_RefreshMelt * -PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session, - struct PERF_TALER_MINTDB_Coin *coin) -{ - struct TALER_MINTDB_RefreshMelt *melt; - struct TALER_CoinSpendSignatureP coin_sig; - struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; - - { - struct - { - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode session; - } to_sign; - - to_sign.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_TEST; - to_sign.purpose.size = htonl (sizeof (to_sign)); - to_sign.session = *session; - GNUNET_CRYPTO_eddsa_sign (&coin->priv, - &to_sign.purpose, - &coin_sig.eddsa_signature); - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.1", - &amount)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.1", - &amount_with_fee)); - melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt); - melt->coin.coin_pub = coin->public_info.coin_pub; - melt->coin.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (coin->public_info.denom_sig.rsa_signature); - melt->coin.denom_pub.rsa_public_key = - GNUNET_CRYPTO_rsa_public_key_dup (coin->public_info.denom_pub.rsa_public_key); - GNUNET_assert (NULL != melt->coin.denom_pub.rsa_public_key); - GNUNET_assert (NULL != melt->coin.denom_sig.rsa_signature); - melt->coin_sig = coin_sig; - melt->session_hash = *session; - melt->amount_with_fee = amount; - melt->melt_fee = amount_with_fee; - return melt; -} - - -/** - * Copies the internals of a #TALER_MINTDB_RefreshMelt - * - * @param melt the refresh melt to copy - * @return an copy of @ melt - */ -struct TALER_MINTDB_RefreshMelt * -PERF_TALER_MINTDB_refresh_melt_copy (const struct TALER_MINTDB_RefreshMelt *melt) -{ - struct TALER_MINTDB_RefreshMelt *copy; - - copy = GNUNET_new (struct TALER_MINTDB_RefreshMelt); - *copy = *melt; - copy->coin.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_signature_dup (melt->coin.denom_sig.rsa_signature); - GNUNET_assert (NULL != copy->coin.denom_sig.rsa_signature); - - return copy; -} - - -/** - * Free the internal memory of a #TALER_MINTDB_RefreshMelt - * - * @param melt the #TALER_MINTDB_RefreshMelt to free - * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR - */ -int -PERF_TALER_MINTDB_refresh_melt_free (struct TALER_MINTDB_RefreshMelt *melt) -{ - GNUNET_CRYPTO_rsa_signature_free (melt->coin.denom_sig.rsa_signature); - GNUNET_free (melt); - return GNUNET_OK; -} - - -/** - * Create a #TALER_MINTDB_RefreshCommitCoin - */ -struct TALER_MINTDB_RefreshCommitCoin * -PERF_TALER_MINTDB_refresh_commit_coin_init () -{ - struct TALER_MINTDB_RefreshCommitCoin *commit_coin; - struct TALER_RefreshLinkEncrypted refresh_link; - - commit_coin = GNUNET_new (struct TALER_MINTDB_RefreshCommitCoin); - GNUNET_assert (NULL != commit_coin); - {/* refresh_link */ - refresh_link = (struct TALER_RefreshLinkEncrypted) - { - .blinding_key_enc = "blinding_key", - .blinding_key_enc_size = 13 - }; - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &refresh_link.coin_priv_enc, - sizeof(struct TALER_CoinSpendPrivateKeyP)); - } - commit_coin->coin_ev = "coin_ev"; - commit_coin->coin_ev_size = 8; - commit_coin->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted); - *commit_coin->refresh_link = refresh_link; - return commit_coin; -} - - -/** - * Copies a #TALER_MINTDB_RefreshCommitCoin - * - * @param commit_coin the commit to copy - * @return a copy of @a commit_coin - */ -struct TALER_MINTDB_RefreshCommitCoin * -PERF_TALER_MINTDB_refresh_commit_coin_copy (struct TALER_MINTDB_RefreshCommitCoin *commit_coin) -{ - struct TALER_MINTDB_RefreshCommitCoin *copy; - - copy = GNUNET_new (struct TALER_MINTDB_RefreshCommitCoin); - copy->refresh_link = GNUNET_new (struct TALER_RefreshLinkEncrypted); - *copy->refresh_link = *commit_coin->refresh_link; - return copy; -} - - -/** - * Free a #TALER_MINTDB_RefreshCommitCoin - * - * @param commit_coin the coin to free - */ -void -PERF_TALER_MINTDB_refresh_commit_coin_free (struct TALER_MINTDB_RefreshCommitCoin *commit_coin) -{ - GNUNET_free (commit_coin->refresh_link); - GNUNET_free (commit_coin); -} diff --git a/src/mintdb/perf_taler_mintdb_init.h b/src/mintdb/perf_taler_mintdb_init.h deleted file mode 100644 index f94beef10..000000000 --- a/src/mintdb/perf_taler_mintdb_init.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/perf_taler_mintdb_init.h - * @brief Heler function for creating dummy inputs for the mint database - * @author Nicolas Fournier - */ -#ifndef __PERF_TALER_MINTDB_INIT_H___ -#define __PERF_TALER_MINTDB_INIT_H___ - -#include "taler_mintdb_plugin.h" - - -#define CURRENCY "EUR" - -/** - * All information about a reserve - */ -struct PERF_TALER_MINTDB_Reserve -{ - /** - * Information about a rserve available to the Mint - */ - struct TALER_MINTDB_Reserve reserve; - - /** - * Private key of a reserve - */ - struct GNUNET_CRYPTO_EddsaPrivateKey private; -}; - - -/** - * All informations about a coin - */ -struct PERF_TALER_MINTDB_Coin -{ - /** - * Blinded coin, known by the mint - */ - struct TALER_MINTDB_CollectableBlindcoin blind; - - /** - * Public key of the coin and othes informations - */ - struct TALER_CoinPublicInfo public_info; - - /** - * Private key of the coin - */ - struct GNUNET_CRYPTO_EddsaPrivateKey priv; -}; - - -/** - * Generate a dummy DenominationKeyInformation for testing purposes - * @return a dummy denomination key - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -PERF_TALER_MINTDB_denomination_init (void); - - -/** - * Copies the given denomination - * @param reserve the deposit copy - * @return a copy of @a deposit; NULL if error - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -PERF_TALER_MINTDB_denomination_copy ( - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki); - - -/** - * Free memory of a DenominationKeyIssueInformation - * @param dki pointer to the struct to free - */ -int -PERF_TALER_MINTDB_denomination_free ( - struct TALER_MINTDB_DenominationKeyIssueInformation *dki); - - -/** - * Generate a dummy reserve for testing - * @return a reserve with 1000 EUR in it - */ -struct PERF_TALER_MINTDB_Reserve * -PERF_TALER_MINTDB_reserve_init (void); - - -/** - * Copies the given reserve - * @param reserve the reserve to copy - * @return a copy of @a reserve; NULL if error - */ -struct PERF_TALER_MINTDB_Reserve * -PERF_TALER_MINTDB_reserve_copy (const struct PERF_TALER_MINTDB_Reserve *reserve); - - -/** - * Free memory of a reserve - * @param reserve pointer to the structure to be freed - */ -int -PERF_TALER_MINTDB_reserve_free (struct PERF_TALER_MINTDB_Reserve *reserve); - - -/** - * Generate a dummy deposit for testing purposes - * @param dki the denomination key used to sign the key - */ -struct TALER_MINTDB_Deposit * -PERF_TALER_MINTDB_deposit_init ( - const struct PERF_TALER_MINTDB_Coin *coin); - - -/** - * Copies the given deposit - * @param reserve the deposit copy - * @return a copy of @a deposit; NULL if error - */ -struct TALER_MINTDB_Deposit * -PERF_TALER_MINTDB_deposit_copy (const struct TALER_MINTDB_Deposit *deposit); - - -/** - * Free memory of a deposit - * @param deposit pointer to the structure to free - */ -int -PERF_TALER_MINTDB_deposit_free (struct TALER_MINTDB_Deposit *deposit); - - -/** - * Generate a coin for testing purpuses - * @param dki denomination key used to sign the coin - * @param reserve reserve providing the money for the coin - * @return a randomly generated CollectableBlindcoin - */ -struct PERF_TALER_MINTDB_Coin * -PERF_TALER_MINTDB_coin_init ( - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki, - const struct PERF_TALER_MINTDB_Reserve *reserve); - - -/** - * Copies the given coin - * @param coin the coin to copy - * @return a copy of coin; NULL if error - */ -struct PERF_TALER_MINTDB_Coin * -PERF_TALER_MINTDB_coin_copy ( - const struct PERF_TALER_MINTDB_Coin *coin); - - -/** - * Liberate memory of @a coin - * @param coin pointer to the structure to free - */ -int -PERF_TALER_MINTDB_coin_free ( - struct PERF_TALER_MINTDB_Coin *coin); - - -/** - * @return a randomly generated refresh session - */ -struct TALER_MINTDB_RefreshSession * -PERF_TALER_MINTDB_refresh_session_init (void); - - -/** - * @return #GNUNET_OK if the copy was successful, #GNUNET_SYSERR if it wasn't - */ -int -PERF_TALER_MINTDB_refresh_session_copy (struct TALER_MINTDB_RefreshSession *session, - struct TALER_MINTDB_RefreshSession *copy); - - -/** - * Frees memory of a refresh_session - */ -int -PERF_TALER_MINTDB_refresh_session_free ( - struct TALER_MINTDB_RefreshSession *refresh_session); - - -/** - * Create a melt operation - * - * @param session the refresh session - * @param dki the denomination the melted coin uses - * @return a pointer to a #TALER_MINTDB_RefreshMelt - */ -struct TALER_MINTDB_RefreshMelt * -PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session, - struct PERF_TALER_MINTDB_Coin *coin); - - -/** - * Copies the internals of a #TALER_MINTDB_RefreshMelt - * - * @param melt the refresh melt to copy - * @return an copy of @ melt - */ -struct TALER_MINTDB_RefreshMelt * -PERF_TALER_MINTDB_refresh_melt_copy (const struct TALER_MINTDB_RefreshMelt *melt); - - -/** - * Free the internal memory of a #TALER_MINTDB_RefreshMelt - * - * @param melt the #TALER_MINTDB_RefreshMelt to free - * @return #GNUNET_OK if the operation was successful, #GNUNET_SYSERROR - */ -int -PERF_TALER_MINTDB_refresh_melt_free (struct TALER_MINTDB_RefreshMelt *melt); - - -/** - * Create a #TALER_MINTDB_RefreshCommitCoin - */ -struct TALER_MINTDB_RefreshCommitCoin * -PERF_TALER_MINTDB_refresh_commit_coin_init (void); - - -/** - * Copies a #TALER_MINTDB_RefreshCommitCoin - * - * @param commit_coin the commit to copy - * @return a copy of @a commit_coin - */ -struct TALER_MINTDB_RefreshCommitCoin * -PERF_TALER_MINTDB_refresh_commit_coin_copy (struct TALER_MINTDB_RefreshCommitCoin *commit_coin); - - -/** - * Free a #TALER_MINTDB_RefreshCommitCoin - * - * @param commit_coin the coin to free - */ -void -PERF_TALER_MINTDB_refresh_commit_coin_free (struct TALER_MINTDB_RefreshCommitCoin *commit_coin); - -#endif diff --git a/src/mintdb/perf_taler_mintdb_interpreter.c b/src/mintdb/perf_taler_mintdb_interpreter.c deleted file mode 100644 index 293d5f35f..000000000 --- a/src/mintdb/perf_taler_mintdb_interpreter.c +++ /dev/null @@ -1,1998 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/perf_taler_mintdb_interpreter.c - * @brief Interpreter library for mint database performance analysis - * @author Nicolas Fournier - */ -#include "platform.h" -#include "perf_taler_mintdb_interpreter.h" -#include "perf_taler_mintdb_init.h" -#include "gauger.h" - - -/** - * Represents the state of the interpreter - */ -struct PERF_TALER_MINTDB_interpreter_state -{ - /** - * State of the commands - */ - struct PERF_TALER_MINTDB_Cmd *cmd; - - /** - * Database plugin - */ - struct TALER_MINTDB_Plugin *plugin; - - /** - * Current database session - */ - struct TALER_MINTDB_Session *session; - - /** - * The current index of the interpreter - */ - unsigned int i; -}; - - -/** - * Free the memory of @a data - */ -static void -data_free (struct PERF_TALER_MINTDB_Data *data) -{ - switch (data->type) - { - case PERF_TALER_MINTDB_TIME: - if (NULL == data->data.time) - break; - GNUNET_free (data->data.time); - data->data.time = NULL; - break; - - case PERF_TALER_MINTDB_DEPOSIT: - if (NULL == data->data.deposit) - break; - PERF_TALER_MINTDB_deposit_free (data->data.deposit); - data->data.deposit = NULL; - break; - - case PERF_TALER_MINTDB_COIN: - if (NULL == data->data.coin) - break; - PERF_TALER_MINTDB_coin_free (data->data.coin); - data->data.coin = NULL; - break; - - case PERF_TALER_MINTDB_RESERVE: - if (NULL == data->data.reserve) - break; - PERF_TALER_MINTDB_reserve_free (data->data.reserve); - data->data.reserve = NULL; - break; - - case PERF_TALER_MINTDB_DENOMINATION_INFO: - if (NULL == data->data.dki) - break; - PERF_TALER_MINTDB_denomination_free (data->data.dki); - data->data.dki = NULL; - break; - - case PERF_TALER_MINTDB_REFRESH_HASH: - if (NULL == data->data.session_hash) - break; - GNUNET_free (data->data.session_hash); - data->data.session_hash = NULL; - break; - - case PERF_TALER_MINTDB_REFRESH_MELT: - if (NULL == data->data.refresh_melt) - break; - PERF_TALER_MINTDB_refresh_melt_free (data->data.refresh_melt); - data->data.refresh_melt = NULL; - break; - - case PERF_TALER_MINTDB_NONE: - break; - } -} - - -/** - * Copies @a data into @a copy - * - * @param data the data to be copied - * @param[out] copy the copy made - */ -static void -data_copy (const struct PERF_TALER_MINTDB_Data *data, - struct PERF_TALER_MINTDB_Data *copy) -{ - copy->type = data->type; - switch (data->type) - { - case PERF_TALER_MINTDB_TIME: - copy->data.time = GNUNET_new (struct GNUNET_TIME_Absolute); - *copy->data.time = *data->data.time; - return; - - case PERF_TALER_MINTDB_DEPOSIT: - copy->data.deposit - = PERF_TALER_MINTDB_deposit_copy (data->data.deposit); - return; - - case PERF_TALER_MINTDB_COIN: - copy->data.coin - = PERF_TALER_MINTDB_coin_copy (data->data.coin); - return; - - case PERF_TALER_MINTDB_RESERVE: - copy->data.reserve - = PERF_TALER_MINTDB_reserve_copy (data->data.reserve); - return; - - case PERF_TALER_MINTDB_DENOMINATION_INFO: - copy->data.dki - = PERF_TALER_MINTDB_denomination_copy (data->data.dki); - return; - - case PERF_TALER_MINTDB_REFRESH_HASH: - copy-> data.session_hash = GNUNET_new (struct GNUNET_HashCode); - *copy->data.session_hash - = *data->data.session_hash; - break; - - case PERF_TALER_MINTDB_REFRESH_MELT: - copy->data.refresh_melt - = PERF_TALER_MINTDB_refresh_melt_copy (data->data.refresh_melt); - break; - - case PERF_TALER_MINTDB_NONE: - break; - } -} - - -/** - * Finds the first command in cmd with the name search - * - * @return the index of the first command with name search - * #GNUNET_SYSERR if none found - */ -static int -cmd_find (const struct PERF_TALER_MINTDB_Cmd *cmd, - const char *search) -{ - unsigned int i; - - for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++) - if (0 == strcmp (cmd[i].label, search)) - return i; - return GNUNET_SYSERR; -} - - -/** - * Initialization of a command array - * and check for the type of the label - * - * @param cmd the comand array initialized - * @return #GNUNET_OK if the initialization was sucessful - * #GNUNET_SYSERR if there was a probleb. See the log for details - */ -static int -cmd_init (struct PERF_TALER_MINTDB_Cmd cmd[]) -{ - unsigned int i; - - for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++) - { - switch (cmd[i].command) - { - case PERF_TALER_MINTDB_CMD_END_LOOP: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.end_loop.label_loop); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.end_loop.label_loop); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.end_loop.label_loop); - return GNUNET_SYSERR; - } - cmd[i].details.end_loop.index_loop = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_SAVE_ARRAY: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.save_array.label_save); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.save_array.label_save); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_NONE == cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.save_array.label_save); - return GNUNET_SYSERR; - } - cmd[i].details.save_array.index_save = ret; - - ret = cmd_find (cmd, - cmd[i].details.save_array.label_loop); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.save_array.label_loop); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.save_array.label_loop); - return GNUNET_SYSERR; - } - cmd[i].details.save_array.index_loop = ret; - - GNUNET_assert (NULL == cmd[i].details.save_array.data_saved); - cmd[i].details.save_array.data_saved = - GNUNET_new_array (cmd[i].details.save_array.nb_saved, - struct PERF_TALER_MINTDB_Data); - cmd[i].details.save_array.type_saved = - cmd[cmd[i].details.save_array.index_save].exposed.type; - } - break; - - case PERF_TALER_MINTDB_CMD_LOAD_ARRAY: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.load_array.label_save); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.load_array.label_save); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_CMD_SAVE_ARRAY != cmd[ret].command) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.load_array.label_save); - return GNUNET_SYSERR; - } - cmd[i].details.load_array.index_save = ret; - - ret = cmd_find (cmd, - cmd[i].details.load_array.label_loop); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.load_array.label_loop); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_CMD_LOOP != cmd[ret].command) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.load_array.label_loop); - return GNUNET_SYSERR; - } - cmd[i].details.load_array.index_loop = ret; - - cmd[i].details.load_array.permutation = - GNUNET_CRYPTO_random_permute ( - GNUNET_CRYPTO_QUALITY_WEAK, - cmd[cmd[i].details.load_array.index_save].details.save_array.nb_saved); - GNUNET_assert (NULL != cmd[i].details.load_array.permutation); - - cmd[i].exposed.type = cmd[cmd[i].details.load_array.index_save].details.save_array.type_saved; - } - break; - - case PERF_TALER_MINTDB_CMD_LOAD_RANDOM: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.load_random.label_save); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.load_random.label_save); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_CMD_SAVE_ARRAY != cmd[ret].command) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.load_random.label_save); - return GNUNET_SYSERR; - } - cmd[i].details.load_random.index_save = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GAUGER: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.gauger.label_start); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.gauger.label_start); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_TIME != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.gauger.label_start); - return GNUNET_SYSERR; - } - cmd[i].details.gauger.index_start = ret; - - ret = cmd_find (cmd, - cmd[i].details.gauger.label_stop); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.gauger.label_stop); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_TIME != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.gauger.label_stop); - return GNUNET_SYSERR; - } - cmd[i].details.gauger.index_stop = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.insert_denomination.label_denom); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_denomination.label_denom); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_denomination.label_denom); - return GNUNET_SYSERR; - } - cmd[i].details.insert_denomination.index_denom = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_DENOMINATION: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_denomination.label_denom); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_denomination.label_denom); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_denomination.label_denom); - return GNUNET_SYSERR; - } - cmd[i].details.get_denomination.index_denom = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_RESERVE: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.insert_reserve.label_reserve); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_reserve.label_reserve); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_reserve.label_reserve); - return GNUNET_SYSERR; - } - cmd[i].details.insert_reserve.index_reserve = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_RESERVE: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_reserve.label_reserve); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_reserve.label_reserve); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_reserve.label_reserve); - return GNUNET_SYSERR; - } - cmd[i].details.get_reserve.index_reserve = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_reserve_history.label_reserve); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_reserve_history.label_reserve); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_reserve_history.label_reserve); - return GNUNET_SYSERR; - } - cmd[i].details.get_reserve_history.index_reserve = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.create_withdraw.label_dki); - { - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.create_withdraw.label_dki); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.create_withdraw.label_dki); - return GNUNET_SYSERR; - } - } - cmd[i].details.create_withdraw.index_dki = ret; - ret = cmd_find (cmd, - cmd[i].details.create_withdraw.label_reserve); - { - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.create_withdraw.label_reserve); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_RESERVE != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.create_withdraw.label_reserve); - return GNUNET_SYSERR; - } - } - cmd[i].details.create_withdraw.index_reserve = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.insert_withdraw.label_coin); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_withdraw.label_coin); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_withdraw.label_coin); - return GNUNET_SYSERR; - } - cmd[i].details.insert_withdraw.index_coin = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_WITHDRAW: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_withdraw.label_coin); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_withdraw.label_coin); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_withdraw.label_coin); - return GNUNET_SYSERR; - } - cmd[i].details.get_withdraw.index_coin = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_coin_transaction.label_coin); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_coin_transaction.label_coin); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_coin_transaction.label_coin); - return GNUNET_SYSERR; - } - cmd[i].details.get_coin_transaction.index_coin = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.create_deposit.label_coin); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.create_deposit.label_coin); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.create_deposit.label_coin); - return GNUNET_SYSERR; - } - cmd[i].details.create_deposit.index_coin = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT: - { - int ret; - - ret = cmd_find( cmd, - cmd[i].details.insert_deposit.label_deposit); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_deposit.label_deposit); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DEPOSIT != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_deposit.label_deposit); - return GNUNET_SYSERR; - } - cmd[i].details.insert_deposit.index_deposit = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_DEPOSIT: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_deposit.label_deposit); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_deposit.label_deposit); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DEPOSIT != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_deposit.label_deposit); - return GNUNET_SYSERR; - } - cmd[i].details.get_deposit.index_deposit = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.get_refresh_session.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_refresh_session.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_refresh_session.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_refresh_session.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT: - { - int ret; - - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_melt.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_melt.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_melt.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_melt.index_hash = ret; - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_melt.label_coin); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_melt.label_coin); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_COIN != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_melt.label_coin); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_melt.index_coin = ret; } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_refresh_melt.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_refresh_melt.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_refresh_melt.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_refresh_melt.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_order.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_order.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_order.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_order.index_hash = ret; - - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_order.label_denom); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_order.label_denom); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_DENOMINATION_INFO != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_order.label_denom); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_order.index_denom = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_refresh_order.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_refresh_order.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_refresh_order.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_refresh_order.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_commit_coin.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_commit_coin.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_commit_coin.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_commit_coin.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_refresh_commit_coin.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_refresh_commit_coin.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_refresh_commit_coin.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_refresh_commit_coin.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_commit_link.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_commit_link.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_commit_link.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_commit_link.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_refresh_commit_link.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_refresh_commit_link.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_refresh_commit_link.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_refresh_commit_link.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_melt_commitment.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_melt_commitment.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_melt_commitment.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_melt_commitment.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.insert_refresh_out.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.insert_refresh_out.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.insert_refresh_out.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.insert_refresh_out.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_link_data_list.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_link_data_list.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_link_data_list.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_link_data_list.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_TRANSFER: - { - int ret; - ret = cmd_find (cmd, - cmd[i].details.get_transfer.label_hash); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Undefined reference to %s\n", - i, - cmd[i].details.get_transfer.label_hash); - return GNUNET_SYSERR; - } - if (PERF_TALER_MINTDB_REFRESH_HASH != cmd[ret].exposed.type) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%d:Wrong type reference to %s\n", - i, - cmd[i].details.get_transfer.label_hash); - return GNUNET_SYSERR; - } - cmd[i].details.get_transfer.index_hash = ret; - } - break; - - case PERF_TALER_MINTDB_CMD_END: - case PERF_TALER_MINTDB_CMD_DEBUG: - case PERF_TALER_MINTDB_CMD_LOOP: - case PERF_TALER_MINTDB_CMD_NEW_SESSION: - case PERF_TALER_MINTDB_CMD_START_TRANSACTION: - case PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION: - case PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION: - case PERF_TALER_MINTDB_CMD_GET_TIME: - case PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION: - case PERF_TALER_MINTDB_CMD_CREATE_RESERVE: - case PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION: - break; - } - } - return GNUNET_OK; -} - - -/** - * Free the memory of the command chain - */ -static int -cmd_clean (struct PERF_TALER_MINTDB_Cmd cmd[]) -{ - unsigned int i; - - for (i=0; PERF_TALER_MINTDB_CMD_END != cmd[i].command; i++) - { - switch (cmd[i].command) - { - case PERF_TALER_MINTDB_CMD_SAVE_ARRAY: - { - unsigned int j; - - for (j = 0; j < cmd[i].details.save_array.nb_saved; j++) - { - data_free (&cmd[i].details.save_array.data_saved[j]); - } - GNUNET_free (cmd[i].details.save_array.data_saved); - cmd[i].details.save_array.data_saved = NULL; - } - break; - - case PERF_TALER_MINTDB_CMD_LOAD_ARRAY: - GNUNET_free (cmd[i].details.load_array.permutation); - cmd[i].details.load_array.permutation = NULL; - break; - - default: - break; - } - data_free (&cmd[i].exposed); - } - return GNUNET_OK; -} - - -/** - * Handles the command #PERF_TALER_MINTDB_CMD_END_LOOP for the interpreter - * Cleans the memory at the end of the loop - */ -static void -interpret_end_loop (struct PERF_TALER_MINTDB_interpreter_state *state) -{ - unsigned int i; - int jump; - - jump = state->cmd[state->i].details.end_loop.index_loop; - // Cleaning up the memory in the loop - for (i = jump; i < state->i; i++) - data_free (&state->cmd[i].exposed); - - state->cmd[jump].details.loop.curr_iteration++; - /* If the loop is not finished */ - if (state->cmd[jump].details.loop.max_iterations > - state->cmd[jump].details.loop.curr_iteration) - { - /* jump back to the start */ - state->i = jump; - } - else - { - /* Reset the loop counter and continue running */ - state->cmd[jump].details.loop.curr_iteration = 0; - } -} - - -/** - * Part of the interpreter specific to - * #PERF_TALER_MINTDB_CMD_SAVE_ARRAY - * Saves the data exposed by another command into - * an array in the command specific struct. - */ -static void -interpret_save_array (struct PERF_TALER_MINTDB_interpreter_state *state) -{ - struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i]; - struct PERF_TALER_MINTDB_Cmd *save_ref; - struct PERF_TALER_MINTDB_Cmd *loop_ref; - int loop_index; - int save_index; - unsigned int selection_chance; - - loop_index = cmd->details.save_array.index_loop; - save_index = cmd->details.save_array.index_save; - loop_ref = &state->cmd[loop_index]; - save_ref = &state->cmd[save_index]; - /* Array initialization on first loop iteration - Alows for nested loops */ - if (0 == cmd->details.loop.curr_iteration) - { - cmd->details.save_array.index = 0; - } - /* The probability distribution of the saved items will be a little biased - against the few last items but it should not be a big problem. */ - selection_chance = loop_ref->details.loop.max_iterations / - cmd->details.save_array.nb_saved; - /* - * If the remaining space is equal to the remaining number of - * iterations, the item is automaticly saved. - * - * Else it is saved only if the random numbre generated is 0 - */ - if ( (0 < (cmd->details.save_array.nb_saved - - cmd->details.save_array.index) ) && - ( ((loop_ref->details.loop.max_iterations - - loop_ref->details.loop.curr_iteration) == - (cmd->details.save_array.nb_saved - - cmd->details.save_array.index)) || - (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - selection_chance)) ) ) - { - struct PERF_TALER_MINTDB_Data *save_location; - struct PERF_TALER_MINTDB_Data *item_saved; - - save_location = &cmd->details.save_array.data_saved[cmd->details.save_array.index]; - item_saved = &save_ref->exposed; - data_copy (item_saved, save_location); - cmd->details.save_array.index++; - } -} - - -/** - * Part of the interpreter specific to - * #PERF_TALER_MINTDB_CMD_LOAD_ARRAY - * Gets data from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY and exposes a copy - */ -static void -interpret_load_array (struct PERF_TALER_MINTDB_interpreter_state *state) -{ - struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i]; - unsigned int loop_iter; - int loop_index; - int save_index; - struct PERF_TALER_MINTDB_Data *loaded_data; - - loop_index = cmd->details.load_array.index_loop; - save_index = cmd->details.load_array.index_save; - loop_iter = state->cmd[loop_index].details.loop.curr_iteration; - { - unsigned int i; - unsigned int quotient; - - /* In case the iteration number is higher than the amount saved, - * the number is run several times in the permutation array */ - quotient = loop_iter / state->cmd[save_index].details.save_array.nb_saved; - loop_iter = loop_iter % state->cmd[save_index].details.save_array.nb_saved; - for (i=0; i<=quotient; i++) - loop_iter = cmd->details.load_array.permutation[loop_iter]; - } - /* Extracting the data from the loop_indexth indice in save_index - * array. - */ - loaded_data = &state->cmd[save_index].details.save_array.data_saved[loop_iter]; - data_copy (loaded_data, - &cmd->exposed); -} - - -/** - * Part of the interpreter specific to - * #PERF_TALER_MINTDB_CMD_LOAD_RANDOM - * Get a random element from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY and exposes it - */ -static void -interprete_load_random (struct PERF_TALER_MINTDB_interpreter_state *state) -{ - struct PERF_TALER_MINTDB_Cmd *cmd = &state->cmd[state->i]; - unsigned int index; - int save_index; - - save_index = cmd->details.load_random.index_save; - index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - state->cmd[save_index].details.save_array.nb_saved); - data_copy (&state->cmd[save_index].details.save_array.data_saved[index], - &cmd->exposed); -} - - -/** - * Iterate over the commands, acting accordingly at each step - * - * @param state the current state of the interpreter - */ -static int -interpret (struct PERF_TALER_MINTDB_interpreter_state *state) -{ - for (state->i=0; PERF_TALER_MINTDB_CMD_END != state->cmd[state->i].command; state->i++) - { - switch (state->cmd[state->i].command) - { - case PERF_TALER_MINTDB_CMD_END: - return GNUNET_YES; - - case PERF_TALER_MINTDB_CMD_DEBUG: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "%s\n", - state->cmd[state->i].label); - break; - - case PERF_TALER_MINTDB_CMD_LOOP: - break; - - case PERF_TALER_MINTDB_CMD_END_LOOP: - interpret_end_loop (state); - break; - - case PERF_TALER_MINTDB_CMD_GET_TIME: - state->cmd[state->i].exposed.data.time = - GNUNET_new (struct GNUNET_TIME_Absolute); - *state->cmd[state->i].exposed.data.time = - GNUNET_TIME_absolute_get (); - break; - - case PERF_TALER_MINTDB_CMD_GAUGER: - { - unsigned int start_index; - unsigned int stop_index; - float ips; - struct GNUNET_TIME_Absolute start; - struct GNUNET_TIME_Absolute stop; - struct GNUNET_TIME_Relative elapsed; - - start_index = state->cmd[state->i].details.gauger.index_start; - stop_index = state->cmd[state->i].details.gauger.index_stop; - start = *state->cmd[start_index].exposed.data.time; - stop = *state->cmd[stop_index].exposed.data.time; - elapsed = GNUNET_TIME_absolute_get_difference (start, - stop); - ips = (1.0 * state->cmd[state->i].details.gauger.divide) / (elapsed.rel_value_us/1000000.0); - GAUGER (state->cmd[state->i].details.gauger.category, - state->cmd[state->i].details.gauger.description, - ips, - state->cmd[state->i].details.gauger.unit); - } - break; - - case PERF_TALER_MINTDB_CMD_NEW_SESSION: - state->session = state->plugin->get_session (state->plugin->cls, GNUNET_YES); - break; - - case PERF_TALER_MINTDB_CMD_START_TRANSACTION: - state->plugin->start (state->plugin->cls, state->session); - break; - - case PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION: - state->plugin->commit (state->plugin->cls, state->session); - break; - - case PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION: - state->plugin->rollback (state->plugin->cls, - state->session); - break; - - case PERF_TALER_MINTDB_CMD_SAVE_ARRAY: - interpret_save_array (state); - break; - - case PERF_TALER_MINTDB_CMD_LOAD_ARRAY: - interpret_load_array (state); - break; - - case PERF_TALER_MINTDB_CMD_LOAD_RANDOM: - interprete_load_random (state); - break; - - case PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT: - { - int coin_index; - struct TALER_MINTDB_Deposit *deposit; - - coin_index = state->cmd[state->i].details.create_deposit.index_coin; - deposit = PERF_TALER_MINTDB_deposit_init (state->cmd[coin_index].exposed.data.coin); - GNUNET_assert (NULL != deposit); - state->cmd[state->i].exposed.data.deposit = deposit; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT: - { - int deposit_index; - int ret; - struct TALER_MINTDB_Deposit *deposit; - - deposit_index = state->cmd[state->i].details.insert_deposit.index_deposit; - deposit = state->cmd[deposit_index].exposed.data.deposit; - ret = state->plugin->insert_deposit (state->plugin->cls, - state->session, - deposit); - GNUNET_assert (GNUNET_SYSERR != ret); - state->cmd[state->i].exposed.data.deposit = deposit; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_DEPOSIT: - { - unsigned int source_index; - int ret; - struct PERF_TALER_MINTDB_Data *data; - - source_index = state->cmd[state->i].details.get_deposit.index_deposit; - data = &state->cmd[source_index].exposed; - ret = state->plugin->have_deposit (state->plugin->cls, - state->session, - data->data.deposit); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_RESERVE: - { - struct PERF_TALER_MINTDB_Reserve *reserve; - - reserve = PERF_TALER_MINTDB_reserve_init (); - state->cmd[state->i].exposed.data.reserve = reserve; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_RESERVE: - { - unsigned int reserve_index; - int ret; - struct PERF_TALER_MINTDB_Reserve *reserve; - json_t *details = NULL; - - reserve_index = state->cmd[state->i].details.insert_reserve.index_reserve; - reserve = state->cmd[reserve_index].exposed.data.reserve; - details = json_pack ("{s:i}","justification", - GNUNET_CRYPTO_random_u32 ( - GNUNET_CRYPTO_QUALITY_WEAK, - UINT32_MAX)); - GNUNET_assert (NULL != details); - ret = state->plugin->reserves_in_insert (state->plugin->cls, - state->session, - &reserve->reserve.pub, - &reserve->reserve.balance, - GNUNET_TIME_absolute_get (), - details); - GNUNET_assert (GNUNET_SYSERR != ret); - json_decref (details); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_RESERVE: - { - unsigned int reserve_index; - int ret; - struct PERF_TALER_MINTDB_Data *data; - - - reserve_index = state->cmd[state->i].details.get_reserve.index_reserve; - data = &state->cmd[reserve_index].exposed; - ret = state->plugin->reserve_get (state->plugin->cls, - state->session, - &data->data.reserve->reserve); - GNUNET_assert (GNUNET_OK == ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY: - { - unsigned int reserve_index; - struct TALER_MINTDB_ReserveHistory *history; - struct PERF_TALER_MINTDB_Data *data; - - reserve_index = state->cmd[state->i].details.get_reserve_history.index_reserve; - data = &state->cmd[reserve_index].exposed; - history = state->plugin->get_reserve_history (state->plugin->cls, - state->session, - &data->data.reserve->reserve.pub); - GNUNET_assert (NULL != history); - state->plugin->free_reserve_history (state->plugin->cls, - history); - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION: - { - struct TALER_MINTDB_DenominationKeyIssueInformation *dki = - PERF_TALER_MINTDB_denomination_init (); - GNUNET_assert (NULL != dki); - state->cmd[state->i].exposed.data.dki = dki; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION: - { - unsigned int denom_index; - int ret; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki ; - - denom_index = state->cmd[state->i].details.insert_denomination.index_denom; - dki = state->cmd[denom_index].exposed.data.dki; - ret = state->plugin->insert_denomination_info (state->plugin->cls, - state->session, - &dki->denom_pub, - &dki->issue); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_DENOMINATION: - { - unsigned int denom_index; - int ret; - struct PERF_TALER_MINTDB_Data *data; - - denom_index = state->cmd[state->i].details.get_denomination.index_denom; - data = &state->cmd[denom_index].exposed; - ret = state->plugin->get_denomination_info (state->plugin->cls, - state->session, - &data->data.dki->denom_pub, - &data->data.dki->issue); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW: - { - unsigned int dki_index; - unsigned int reserve_index; - struct PERF_TALER_MINTDB_Coin *coin ; - - dki_index = state->cmd[state->i].details.create_withdraw.index_dki; - reserve_index = state->cmd[state->i].details.create_withdraw.index_reserve; - coin = PERF_TALER_MINTDB_coin_init (state->cmd[dki_index].exposed.data.dki, - state->cmd[reserve_index].exposed.data.reserve); - GNUNET_assert (NULL != coin); - state->cmd[state->i].exposed.data.coin = coin; - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW: - { - unsigned int coin_index; - int ret; - struct PERF_TALER_MINTDB_Coin *coin ; - - coin_index = state->cmd[state->i].details.insert_withdraw.index_coin; - coin = state->cmd[coin_index].exposed.data.coin; - ret = state->plugin->insert_withdraw_info (state->plugin->cls, - state->session, - &coin->blind); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_WITHDRAW: - { - unsigned int source_index; - int ret; - struct PERF_TALER_MINTDB_Data *data; - - source_index = state->cmd[state->i].details.get_denomination.index_denom; - data = &state->cmd[source_index].exposed; - ret = state->plugin->get_withdraw_info (state->plugin->cls, - state->session, - &data->data.coin->blind.h_coin_envelope, - &data->data.coin->blind); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION: - { - unsigned int coin_index; - struct PERF_TALER_MINTDB_Coin *coin; - struct TALER_MINTDB_TransactionList *transactions; - - coin_index = state->cmd[state->i].details.get_coin_transaction.index_coin; - coin = state->cmd[coin_index].exposed.data.coin; - transactions = state->plugin->get_coin_transactions (state->plugin->cls, - state->session, - &coin->public_info.coin_pub); - GNUNET_assert (transactions != NULL); - state->plugin->free_coin_transaction_list (state->plugin->cls, - transactions); - } - break; - - case PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION: - { - struct GNUNET_HashCode *hash; - struct TALER_MINTDB_RefreshSession *refresh_session; - - hash = GNUNET_new (struct GNUNET_HashCode); - refresh_session = PERF_TALER_MINTDB_refresh_session_init (); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - hash); - state->plugin->create_refresh_session (state->session, - state->session, - hash, - refresh_session); - state->cmd[state->i].exposed.data.session_hash = hash; - PERF_TALER_MINTDB_refresh_session_free (refresh_session); - GNUNET_free (refresh_session); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION: - { - unsigned int hash_index; - struct GNUNET_HashCode *hash; - struct TALER_MINTDB_RefreshSession refresh; - - hash_index = state->cmd[state->i].details.get_refresh_session.index_hash; - hash = state->cmd[hash_index].exposed.data.session_hash; - state->plugin->get_refresh_session (state->session, - state->session, - hash, - &refresh); - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT: - { - unsigned int hash_index; - unsigned int coin_index; - struct GNUNET_HashCode *hash; - struct TALER_MINTDB_RefreshMelt *melt; - struct PERF_TALER_MINTDB_Coin *coin; - - hash_index = state->cmd[state->i].details.insert_refresh_melt.index_hash; - coin_index = state->cmd[state->i].details.insert_refresh_melt.index_coin; - hash = state->cmd[hash_index].exposed.data.session_hash; - coin = state->cmd[coin_index].exposed.data.coin; - melt = PERF_TALER_MINTDB_refresh_melt_init (hash, - coin); - state->plugin->insert_refresh_melt (state->plugin->cls, - state->session, - 1, - melt); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT: - { - int ret; - unsigned int hash_index; - struct GNUNET_HashCode *hash; - struct TALER_MINTDB_RefreshMelt melt; - - hash_index = cmd_find (state->cmd, - state->cmd[state->i].details.get_refresh_melt.label_hash); - hash = state->cmd[hash_index].exposed.data.session_hash; - ret = state->plugin->get_refresh_melt (state->plugin->cls, - state->session, - hash, - 1, - &melt); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER: - { - unsigned int hash_index; - unsigned int denom_index; - struct GNUNET_HashCode *session_hash; - struct TALER_MINTDB_DenominationKeyIssueInformation *denom; - - hash_index = state->cmd[state->i].details.insert_refresh_order.index_hash; - denom_index = state->cmd[state->i].details.insert_refresh_order.index_denom; - session_hash = state->cmd[hash_index].exposed.data.session_hash; - denom = state->cmd[denom_index].exposed.data.dki; - state->plugin->insert_refresh_order (state->plugin->cls, - state->session, - session_hash, - 1, - &denom->denom_pub); - - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER: - { - int hash_index; - struct GNUNET_HashCode *hash; - struct TALER_DenominationPublicKey denom_pub; - - hash_index = state->cmd[state->i].details.get_refresh_order.index_hash; - hash = state->cmd[hash_index].exposed.data.session_hash; - state->plugin->get_refresh_order (state->plugin->cls, - state->session, - hash, - 1, - &denom_pub); - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN: - { - int ret; - unsigned int hash_index; - struct TALER_MINTDB_RefreshCommitCoin *refresh_commit; - - hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash; - refresh_commit = PERF_TALER_MINTDB_refresh_commit_coin_init (); - ret = state->plugin->insert_refresh_commit_coins (state->plugin->cls, - state->session, - state->cmd[hash_index].exposed.data.session_hash, - 1, - 1, - refresh_commit); - GNUNET_assert (GNUNET_OK == ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN: - { - unsigned int hash_index; - struct TALER_MINTDB_RefreshCommitCoin refresh_commit; - - hash_index = state->cmd[state->i].details.insert_refresh_commit_coin.index_hash; - state->plugin->get_refresh_commit_coins (state->plugin->cls, - state->session, - state->cmd[hash_index].exposed.data.session_hash, - 1, - 1, - &refresh_commit); - - } - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK: - { -// unsigned int hash_index; -// -// hash_index = state->cmd[state->i].details.insert_refresh_commit_link.index_hash; - } - break; - - case PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK: - { - int ret; - unsigned int hash_index; - struct TALER_MINTDB_RefreshCommitCoin commit_coin; - - hash_index = state->cmd[state->i].details.get_refresh_commit_link.index_hash; - ret = state->plugin->get_refresh_commit_coins(state->plugin->cls, - state->session, - state->cmd[hash_index].exposed.data.session_hash, - 1, - 1, - &commit_coin); - GNUNET_assert (GNUNET_SYSERR != ret); - } - break; - - case PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT: - break; - - case PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT: - break; - - case PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST: - break; - - case PERF_TALER_MINTDB_CMD_GET_TRANSFER: - break; - - } - } - return GNUNET_OK; -} - - -/** - * Runs the commands given in @a cmd, working with - * the database referenced by @a db_plugin - * - * @param db_plugin the connection to the database - * @param cmd the commands to run - */ -int -PERF_TALER_MINTDB_interpret (struct TALER_MINTDB_Plugin *db_plugin, - struct PERF_TALER_MINTDB_Cmd cmd[]) -{ - int ret; - struct PERF_TALER_MINTDB_interpreter_state state = - {.i = 0, .cmd = cmd, .plugin = db_plugin}; - - ret = cmd_init (cmd); - if (GNUNET_SYSERR == ret) - return ret; - state.session = db_plugin->get_session (db_plugin->cls, - GNUNET_YES); - GNUNET_assert (NULL != state.session); - ret = interpret (&state); - cmd_clean (cmd); - return ret; -} - - -/** - * Initialize the database and run the benchmark - * - * @param benchmark_name the name of the benchmark, displayed in the logs - * @param configuration_file path to the taler configuration file to use - * @param init the commands to use for the database initialisation, - * if #NULL the standard initialization is used - * @param benchmark the commands for the benchmark - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -int -PERF_TALER_MINTDB_run_benchmark (const char *benchmark_name, - const char *configuration_file, - struct PERF_TALER_MINTDB_Cmd *init, - struct PERF_TALER_MINTDB_Cmd *benchmark) -{ - struct TALER_MINTDB_Plugin *plugin; - struct GNUNET_CONFIGURATION_Handle *config; - int ret = 0; - struct PERF_TALER_MINTDB_Cmd init_def[] = - { - // Denomination used to create coins - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("00 - Start of interpreter"), - - PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop", - PERF_TALER_MINTDB_NB_DENOMINATION_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", - "01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", - "01 - denomination loop", - "01 - denomination", - PERF_TALER_MINTDB_NB_DENOMINATION_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "01 - denomination loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("01 - init denomination complete"), - // End of initialization - // Reserve initialization - PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop", - PERF_TALER_MINTDB_NB_RESERVE_INIT), - PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert", - "02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", - "02 - init reserve loop", - "02 - reserve", - PERF_TALER_MINTDB_NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "02 - init reserve loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("02 - reserve init complete"), - // End reserve init - // Withdrawal initialization - PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop", - PERF_TALER_MINTDB_NB_WITHDRAW_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", - "03 - init withdraw loop", - "01 - save denomination"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", - "03 - init withdraw loop", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", - "03 - denomination load", - "03 - reserve load"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert", - "03 - withdraw"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION (""), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - save coin", - "03 - init withdraw loop", - "03 - withdraw", - PERF_TALER_MINTDB_NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("", - "03 - init withdraw loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("03 - withdraw init complete"), - //End of withdrawal initialization - //Deposit initialization - PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop", - PERF_TALER_MINTDB_NB_DEPOSIT_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - denomination load", - "04 - deposit init loop", - "03 - save coin"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - deposit", - "04 - denomination load"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", - "04 - deposit init loop", - "04 - deposit", - PERF_TALER_MINTDB_NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("04 - deposit init loop end", - "04 - deposit init loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("04 - deposit init complete"), - // End of deposit initialization - PERF_TALER_MINTDB_INIT_CMD_END ("end") - }; - - GNUNET_log_setup (benchmark_name, - "INFO", - NULL); - config = GNUNET_CONFIGURATION_create (); - - ret = GNUNET_CONFIGURATION_load (config, - configuration_file); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing configuration file\n"); - return GNUNET_SYSERR; - } - plugin = TALER_MINTDB_plugin_load (config); - if (NULL == plugin) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error connectiong to the database\n"); - return ret; - } - ret = plugin->create_tables (plugin->cls, - GNUNET_YES); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error while creating the database architecture\n"); - return ret; - } - /* - * Running the initialization - */ - if (NULL == init) - { - init = init_def; - } - ret = PERF_TALER_MINTDB_interpret (plugin, - init); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error during database initialization\n"); - return ret; - } - /* - * Running the benchmark - */ - ret = PERF_TALER_MINTDB_interpret (plugin, - benchmark); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error while runing the benchmark\n"); - return ret; - } - /* Drop tables */ - { - struct TALER_MINTDB_Session *session; - - session = plugin->get_session (plugin->cls, - GNUNET_YES); - ret = plugin->drop_temporary (plugin->cls, - session); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error cleaning the database\n"); - return ret; - } - } - TALER_MINTDB_plugin_unload (plugin); - GNUNET_CONFIGURATION_destroy (config); - return ret; -} diff --git a/src/mintdb/perf_taler_mintdb_interpreter.h b/src/mintdb/perf_taler_mintdb_interpreter.h deleted file mode 100644 index 3510e3dd4..000000000 --- a/src/mintdb/perf_taler_mintdb_interpreter.h +++ /dev/null @@ -1,1319 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mintdb/perf_taler_mintdb_interpreter.h - * @brief Library for performance analysis of the Taler database - * @author Nicolas Fournier - * - * This library contains functions and macro alowing Taler performance analysis - * to be written with ease. - * To do so, create a #PERF_TALER_MINTDB_Cmd array and fill it with the commands - * to execute in chronological order. Some command have an exposed variable wich - * can be reused in other commands. - * Macros are available to make the use much easier so feel free to use them - * to initialize your own command array. - */ - -#ifndef __PERF_TALER_MINTDB_INTERPRETER_H__ -#define __PERF_TALER_MINTDB_INTERPRETER_H__ - -#include <sys/time.h> -#include "taler_mintdb_plugin.h" - - -#define PERF_TALER_MINTDB_NB_DENOMINATION_INIT 10 -#define PERF_TALER_MINTDB_NB_DENOMINATION_SAVE 10 - -#define PERF_TALER_MINTDB_NB_RESERVE_INIT 100 -#define PERF_TALER_MINTDB_NB_RESERVE_SAVE 10 - -#define PERF_TALER_MINTDB_NB_DEPOSIT_INIT 100 -#define PERF_TALER_MINTDB_NB_DEPOSIT_SAVE 10 - -#define PERF_TALER_MINTDB_NB_WITHDRAW_INIT 100 -#define PERF_TALER_MINTDB_NB_WITHDRAW_SAVE 10 - - -/** - * Marks the end of the command chain - * - * @param _label The label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_END(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_END, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE \ -} - - -/** - * Prints @ _label to stdout - * - * @param _label The label of the command, - * will be logged each time the command runs - */ -#define PERF_TALER_MINTDB_INIT_CMD_DEBUG(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_DEBUG, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE \ -} - -/** - * The begining of a loop - * - * @param _label the label of the loop - * @param _iter the number of iterations of the loop - */ -#define PERF_TALER_MINTDB_INIT_CMD_LOOP(_label, _iter) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_LOOP , \ - .label = _label , \ - .exposed.type = PERF_TALER_MINTDB_NONE , \ - .details.loop = { \ - .max_iterations = _iter , \ - .curr_iteration = 0 } \ -} - -/** - * Marks the end of the loop @_label_loop - * - * @param _label the label of the command - * @param _label_loop the label of the loop closed by this command - */ -#define PERF_TALER_MINTDB_INIT_CMD_END_LOOP(_label, _label_loop) \ -{\ - .command = PERF_TALER_MINTDB_CMD_END_LOOP , \ - .label = _label , \ - .exposed.type = PERF_TALER_MINTDB_NONE , \ - .details.end_loop.label_loop = _label_loop \ -} - -/** - * Saves the time of execution to use for logging with Gauger - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_TIME(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_TIME, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_TIME \ -} - -/** - * Commits the duration between @a _label_start and @a _label_stop - * to Gauger with @a _description explaining what was measured. - * - * @param _label the label of this command - * @param _label_start label of the start of the measurment - * @param _label_stop label of the end of the measurment - * @param _description description of the measure displayed in Gauger - * @param _unit the unit of the data measured, typicly something/sec - * @param _divide number of measurments in the interval - */ -#define PERF_TALER_MINTDB_INIT_CMD_GAUGER(_label, _label_start, _label_stop, _category, _description, _unit, _divide) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GAUGER, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.gauger = { \ - .label_start = _label_start, \ - .label_stop = _label_stop, \ - .category = _category, \ - .description = _description, \ - .unit = _unit, \ - .divide = _divide, \ - } \ -} - -/** - * Initiate a database transaction - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_START_TRANSACTION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ -} - -/** - * Commits a database transaction - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ -} - -/** - * Abort the current transaction - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_ABORT_TRANSACTION(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION, \ - .label = _label, - -/** - * Saves randomly selected items from @a _label_save - * Saved items can latter be access using #PERF_TALER_MINTDB_CMD_LOAD_ARRAY - * - * @param _label the label of the command, used by other commands to reference it - * @param _label_loop the label of the loop the array iterates over - * @param _label_save the label of the command which outout is saved by this command - * @param _nb_saved the total number of items to be saved - */ -#define PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY(_label, _label_loop, _label_save, _nb_saved) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_SAVE_ARRAY, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.save_array = { \ - .label_loop = _label_loop, \ - .label_save = _label_save, \ - .nb_saved = _nb_saved, \ - } \ -} - -/** - * Loads data from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY to allow other - * commands to access it - * - * @param _label the label of this command, referenced by commands to access it's outpout - * @param _label_loop the label of the loop to iterate over - * @param _label_save the label of the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY providing data - */ -#define PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY(_label, _label_loop, _label_save) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_LOAD_ARRAY, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.load_array = { \ - .label_loop = _label_loop, \ - .label_save = _label_save \ - } \ -} - -/** - * Create a denomination key to use - * Exposes a #PERF_TALER_MINTDB_DENOMINATION_INFO to be used by other commands - * @exposed #PERF_TALER_MINTDB_DENOMINATION_INFO - * - * @param _label the label of this command - */ -#define PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_DENOMINATION_INFO, \ -} - -/** - * Inserts informations about a denomination key in the database - * - * @param _label the label of this command - * @param _label_denom the label of the denomination to insert - */ -#define PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION(_label, _label_denom) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.insert_denomination.label_denom = _label_denom, \ -} - -/** - * Polls the database about informations regarding a specific denomination key - * - * @param _label the label of this command - * @param _label_denom the label of the command providing information about the denomination key - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_DENOMINATION(_label, _label_denom) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_DENOMINATION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_denomination.label_denom = _label_denom \ -} - -/** - * Create a reserve to be used later - * Exposes a #PERF_TALER_MINTDB_RESERVE - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_CREATE_RESERVE, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_RESERVE \ -} - -/** - * Insert a new reserve in the database containing 1000 Euros - * - * @param _label the name of this command - * @param _label_reserve the label of the reserve to insert - */ -#define PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE(_label, _label_reserve) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_INSERT_RESERVE, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.insert_reserve.label_reserve = _label_reserve \ -} - -/** - * Polls the database for a secific reserve's details - * - * @param _label the label of this command - * @param _label_reserve the reserve to poll - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE(_label, _label_reserve) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_RESERVE, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_reserve.label_reserve = _label_reserve \ -} - -/** - * Polls the database for the history of a reserve - * - * @param _label the label of the command - * @param _label_reserve the reserve to examine - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY(_label, _label_reserve) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_reserve_history.label_reserve = _label_reserve \ -} - -/** - * Creates a coin to be used later - * - * @param _label the label of this command - * @param _label_dki denomination key used to sign the coin - * @param _label_reserve reserve used to emmit the coin - */ -#define PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW(_label, _label_dki, _label_reserve) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_COIN, \ - .details.create_withdraw = {\ - .label_dki = _label_dki, \ - .label_reserve = _label_reserve, \ - } \ -} - -/** - * Inserts informations about a withdrawal in the database - * - * @exposes #PERF_TALER_MINTDB_COIN - * - * @param _label the label of this command - * @param _label_coin the coin to insert - */ -#define PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW(_label, _label_coin) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.insert_withdraw.label_coin = _label_coin\ -} - - -/** - * Polls the database about informations regarding a specific withdrawal - * - * @param _label the label of this command - * @param _label_coin the coin to check - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_WITHDRAW(_label, _label_coin) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_WITHDRAW, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_withdraw.label_coin = _label_coin, \ -} - - -/** - * The /reserve/withdraw api call - * - * Exposes #PERF_TALER_MINTDB_COIN - * - * @param _label the label of this command - * @param _label_dki the denomination of the created coin - * @param _label_reserve the reserve used to provide currency - */ -#define PERF_TALER_MINTDB_INIT_CMD_WITHDRAW_SIGN(_label, _label_dki, _label_reserve) \ - PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW (_label "withdraw", \ - _label_dki, \ - _label_reserve), \ - PERF_TALER_MINTDB_INIT_CMD_GET_DENOMINATION(_label "withdraw info", \ - _label_dki), \ - PERF_TALER_MINTDB_INIT_CMD_GET_RESERVE_HISTORY(_label "reserve_history", \ - _label_reserve), \ - PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW(_label "insert withdraw", \ - _label "withdraw") - -/** - * Create a deposit for use later - * @exposes #PERF_TALER_MINTDB_DEPOSIT - * - * @param _label the label of this command - * @param _label_coin the coin used to pay - */ -#define PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT(_label, _label_coin) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_DEPOSIT, \ - .details.create_deposit.label_coin = _label_coin, \ -} - -/** - * Insert a deposit into the database - * - * @param _label the label of this command - * @param _label_deposit the deposit inseerted - */ -#define PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT(_label, _label_deposit) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT,\ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.insert_deposit.label_deposit = _label_deposit, \ -} - -/** - * Check if a deposit is in the database - * - * @param _label the label of this command - * @param _label_deposit the deposit to use - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_DEPOSIT(_label, _label_deposit) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_DEPOSIT, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_deposit.label_deposit = _label_deposit \ -} - -/** - * Access the transaction history of a coin - * - * @param _label the label of the command - * @param _label_coin the coin which history is checked - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION(_label, _label_coin) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE, \ - .details.get_coin_transaction.label_coin = _label_coin \ -} - -/** - * The /deposit api call - * - * @param _label the label of the command - * @param _label_coin the coin used for the deposit - */ -#define PERF_TALER_MINTDB_INIT_CMD_DEPOSIT(_label, _label_coin) \ - PERF_TALER_MINTDB_INIT_CMD_GET_COIN_TRANSACTION (_label "coin history", \ - _label_coin), \ - PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT (_label "deposit", \ - _label_coin), \ - PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT (_label "insert", \ - _label "deposit") -/** - * Insert informations about a refresh session - * melts one coin into another - * - * @param _label the label of the command - */ -#define PERF_TALER_MINTDB_INIT_CMD_CREATE_REFRESH_SESSION(_label) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_REFRESH_HASH \ -} - -/** - * Get informations about a refresh session - * - * @param _label the label of the command - * @param _label_hash the label of the hash to search - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_REFRESH_SESSION(_label, \ - _label_hash) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION, \ - .label = _label, \ - .exposed.type = PERF_TALER_MINTDB_NONE \ -} - -/** - * Insert a melt operation in the database - * - * @param _label the label of the command - * @param _label_hash the label of the hash of the session - * @param _label_coin the label of the coin to melt - */ -#define PERF_TALER_MINTDB_INIT_CMD_INSERT_REFRESH_MELT(_label, \ - _label_hash, \ - _label_coin) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT, \ - .label = _label, \ - .details.insert_refresh_melt.label_hash = _label_hash, \ - .details.insert_refresh_melt.label_coin = _label_coin, \ - .exposed.type = PERF_TALER_MINTDB_NONE \ -} - -/** - * Get informations about a melt operation - * - * @param _label the label of the command - * @param _label_hash the label of the hash of the refresh session - */ -#define PERF_TALER_MINTDB_INIT_CMD_GET_REFRESH_MELT(_label, \ - _label_hash) \ -{ \ - .command = PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT, \ - .label = _label, \ - .detail.get_refresh_melt.label_hash = _label_hash, \ - .exposed.type = PERF_TALER_MINTDB_NONE \ -} - -/** - * The type of data stored in #PERF_TALER_MINTDB_Memory - */ -enum PERF_TALER_MINTDB_Type -{ - PERF_TALER_MINTDB_NONE, - PERF_TALER_MINTDB_TIME, - PERF_TALER_MINTDB_DENOMINATION_INFO, - PERF_TALER_MINTDB_RESERVE, - PERF_TALER_MINTDB_COIN, - PERF_TALER_MINTDB_DEPOSIT, - PERF_TALER_MINTDB_REFRESH_HASH, - PERF_TALER_MINTDB_REFRESH_MELT -}; - - -/** - * Structure used to handle several data type - */ -struct PERF_TALER_MINTDB_Data -{ - enum PERF_TALER_MINTDB_Type type; - - /** - * Storage for a variety of data type - * The data saved should match #type - */ - union PERF_TALER_MINTDB_Memory - { - /** #PERF_TALER_MINTDB_TIME */ - struct GNUNET_TIME_Absolute *time; - /** #PERF_TALER_MINTDB_DEPOSIT */ - struct TALER_MINTDB_Deposit *deposit; - /** #PERF_TALER_MINTDB_COIN */ - struct PERF_TALER_MINTDB_Coin *coin; - /** #PERF_TALER_MINTDB_RESERVE */ - struct PERF_TALER_MINTDB_Reserve *reserve; - /** #PERF_TALER_MINTDB_DENOMINATION_INFO */ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - /** #PERF_TALER_MINTDB_REFRESH_HASH */ - struct GNUNET_HashCode *session_hash; - /** #PERF_TALER_MINTDB_REFRESH_MELT */ - struct TALER_MINTDB_RefreshMelt *refresh_melt; - } data; -}; - - -/** - * Name of the command - */ -enum PERF_TALER_MINTDB_CMD_Name -{ - /** - * All comand chain must hace this as their last command - */ - PERF_TALER_MINTDB_CMD_END, - - /** - * Prints it's label - */ - PERF_TALER_MINTDB_CMD_DEBUG, - - /** - * Define the start of al command chain loop - */ - PERF_TALER_MINTDB_CMD_LOOP, - - /** - * Define the end of a command chain loop - */ - PERF_TALER_MINTDB_CMD_END_LOOP, - - /** - * Save the time at which the command was executed - */ - PERF_TALER_MINTDB_CMD_GET_TIME, - - /** - * Upload performance to Gauger - */ - PERF_TALER_MINTDB_CMD_GAUGER, - - /** - * Start a new session - */ - PERF_TALER_MINTDB_CMD_NEW_SESSION, - - /** - * Start a database transaction - */ - PERF_TALER_MINTDB_CMD_START_TRANSACTION, - - /** - * End a database transaction - */ - PERF_TALER_MINTDB_CMD_COMMIT_TRANSACTION, - - /** - * Abort a transaction started with #PERF_TALER_MINTDB_CMD_START_TRANSACTION - */ - PERF_TALER_MINTDB_CMD_ABORT_TRANSACTION, - - /** - * Saves random deposits from a loop - */ - PERF_TALER_MINTDB_CMD_SAVE_ARRAY, - - /** - * Load items saved earlier in a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY - * The items are loaded in a random order, but all of them will be loaded - */ - PERF_TALER_MINTDB_CMD_LOAD_ARRAY, - - /** - * Loads a random item from a #PERF_TALER_MINTDB_CMD_SAVE_ARRAY - * A random item is loaded each time the command is run - */ - PERF_TALER_MINTDB_CMD_LOAD_RANDOM, - - /** - * Create a denomination to be used later - */ - PERF_TALER_MINTDB_CMD_CREATE_DENOMINATION, - - /** - * Insert informations about a denomination key in the database - */ - PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION, - - /** - * Polls the database for informations about a specific denomination key - */ - PERF_TALER_MINTDB_CMD_GET_DENOMINATION, - - /** - * Create a reserve to be used later - */ - PERF_TALER_MINTDB_CMD_CREATE_RESERVE, - - /** - * Insert currency in a reserve / Create a reserve - */ - PERF_TALER_MINTDB_CMD_INSERT_RESERVE, - - /** - * Get Informations about a reserve - */ - PERF_TALER_MINTDB_CMD_GET_RESERVE, - - /** - * Get the history of a reserve - */ - PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY, - - /** - * Create a withdrawal to be used later - */ - PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW, - - /** - * Insert informations about a withdrawal in the database - */ - PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW, - - /** - * Pulls informations about a withdrawal from the database - */ - PERF_TALER_MINTDB_CMD_GET_WITHDRAW, - - /** - * Get the list of all transactions the coin has been in - */ - PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION, - - /** - * Create a deposit to be used later - */ - PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT, - - /** - * Insert a deposit into the database - */ - PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT, - - /** - * Check if a deposit is in the database - */ - PERF_TALER_MINTDB_CMD_GET_DEPOSIT, - - /** - * Create a refresh session - * The number of melted coins is 1, - * The number of minted coins is 1 - */ - PERF_TALER_MINTDB_CMD_CREATE_REFRESH_SESSION, - - /** - * Get a refresh session informations - */ - PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION, - - /** - * Insert a refresh melt - */ - PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT, - - /** - * Get informations about a refresh melt operation - */ - PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT, - - /** - * Insert a melt refresh order - */ - PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER, - - /** - * Get informations about a refresh order - */ - PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER, - - /** - * Insert refresh commit coin - */ - PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN, - - /** - * Get refresh commit coin - */ - PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN, - - /** - * Insert refresh commit link - */ - PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK, - - /** - * Get refresh commit link - */ - PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK, - - /** - * Get information avout the melt commit - */ - PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT, - - /** - * Insert a new coin into the database after a melt operation - */ - PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT, - - /** - * Get the link data list of a coin - */ - PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST, - - /** - * Get the shared secret and the transfere public key - */ - PERF_TALER_MINTDB_CMD_GET_TRANSFER - -}; - - -/** - * Contains extra data required for any command - */ -union PERF_TALER_MINTDB_CMD_Details -{ - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_LOOP command - */ - struct PERF_TALER_MINTDB_CMD_loopDetails - { - /** - * Maximum number of iteration in the loop - */ - const unsigned int max_iterations; - - /** - * The current iteration of the loop - */ - unsigned int curr_iteration; - } loop; - - /** - * Extra data requiered by the #PERF_TALER_MINTDB_CMD_END_LOOP command - */ - struct PERF_TALER_MINTDB_CMD_endLoopDetails - { - /** - * Label of the loop closed by the command - */ - const char *label_loop; - unsigned int index_loop; - } end_loop; - - /** - * Details about the #PERF_TALER_MINTDB_CMD_GAUGER command - */ - struct PERF_TALER_MINTDB_CMD_gaugerDetails - { - /** - * Label of the starting timestamp - */ - const char *label_start; - unsigned int index_start; - - /** - * Label of the ending timestamp - */ - const char *label_stop; - unsigned int index_stop; - - /** - * The category of the measurment - */ - const char *category; - - /** - * Description of the metric, used in Gauger - */ - const char *description; - - /** - * The name of the metric beeing used - */ - const char *unit; - - /** - * Constant the result needs to be divided by - * to get the result per unit - */ - float divide; - } gauger; - - /** - * Contains extra data requiered by the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY command - */ - struct PERF_TALER_MINTDB_CMD_saveArrayDetails - { - /** - * Number of items to save - */ - unsigned int nb_saved; - - /** - * Number of items already saved - */ - unsigned int index; - - /** - * Label of the loop it is attached to - */ - const char *label_loop; - unsigned int index_loop; - - /** - * Label of the command exposing the item - */ - const char *label_save; - unsigned int index_save; - - /** - * Array of data saved - */ - struct PERF_TALER_MINTDB_Data *data_saved; - - /** - * Type of the data that will be stored in @a data_saved, for - * 'static' type checking. - */ - enum PERF_TALER_MINTDB_Type type_saved; - - } save_array; - - /** - * Extra data required for the #PERF_TALER_MINTDB_CMD_LOAD_ARRAY command - */ - struct PERF_TALER_MINTDB_CMD_loadArrayDetails - { - /** - * The loop in which the command is located - */ - const char *label_loop; - unsigned int index_loop; - - /** - * Label of the command where the items were saved - */ - const char *label_save; - unsigned int index_save; - - /** - * A permutation array used to randomize the order the items are loaded in - */ - unsigned int *permutation; - } load_array; - - /** - * Contains data for the #PERF_TALER_MINTDB_CMD_LOAD_RANDOM command - */ - struct PERF_TALER_MINTDB_CMD_loadRandomDetails - { - /** - * The label of the #PERF_TALER_MINTDB_CMD_SAVE_ARRAY the items will be extracted from - */ - const char *label_save; - unsigned int index_save; - } load_random; - - /** - * Extra data requiered by the #PERF_TALER_MINTDB_CMD_INSERT_DENOMINATION command - */ - struct PERF_TALER_MINTDB_CMD_insertDenominationDetails - { - /** - * The label of the source of the denomination to insert - */ - const char *label_denom; - unsigned int index_denom; - } insert_denomination; - - /** - * Extra data requiered by the #PERF_TALER_MINTDB_CMD_GET_DENOMINATION command - */ - struct PERF_TALER_MINTDB_CMD_getDenominationDetails - { - /** - * The label of the source of the denomination to check - */ - const char *label_denom; - unsigned int index_denom; - } get_denomination; - - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_RESERVE command - */ - struct PERF_TALER_MINTDB_CMD_insertReserveDetails - { - /** - * The label of the source of the reserve to insert - */ - const char *label_reserve; - unsigned int index_reserve; - } insert_reserve; - - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_RESERVE command - */ - struct PERF_TALER_MINTDB_CMD_getReserveDetails - { - /** - * The label of the source of the reserve to check - */ - const char *label_reserve; - unsigned int index_reserve; - } get_reserve; - - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_RESERVE_HISTORY command - */ - struct PERF_TALER_MINTDB_CMD_getReserveHistoryDetails - { - /** - * The label of the source of the reserve to check - */ - const char *label_reserve; - unsigned int index_reserve; - } get_reserve_history; - - /** - * Extra data related to the #PERF_TALER_MINTDB_CMD_CREATE_WITHDRAW command - */ - struct PERF_TALER_MINTDB_CMD_createWithdrawDetails - { - /** - * label of the denomination key used to sign the coin - */ - const char *label_dki; - unsigned int index_dki; - - /** - * label of the reserve the money to mint the coin comes from - */ - const char *label_reserve; - unsigned int index_reserve; - } create_withdraw; - - /** - * data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_WITHDRAW - */ - struct PERF_TALER_MINTDB_CMD_insertWithdrawDetails - { - /** - * label of the source for the coin information - */ - const char *label_coin; - unsigned int index_coin; - } insert_withdraw; - - /** - * data requiered for the #PERF_TALER_MINTDB_CMD_GET_WITHDRAW - */ - struct PERF_TALER_MINTDB_CMD_getWithdraw - { - /** - * label of the source for the coin information - */ - const char *label_coin; - unsigned int index_coin; - } get_withdraw; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_COIN_TRANSACTION command - */ - struct PERF_TALER_MINTDB_CMD_getCoinTransactionDetails - { - /** - * The coin which history is checked - */ - const char *label_coin; - unsigned int index_coin; - } get_coin_transaction; - - /** - * Data used by the #PERF_TALER_MINTDB_CMD_CREATE_DEPOSIT command - */ - struct PERF_TALER_MINTDB_CMD_createDepositDetails - { - /** - * Label of the source where the reserve used to create the coin is - */ - const char *label_coin; - unsigned int index_coin; - } create_deposit; - - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_DEPOSIT command - */ - struct PERF_TALER_MINTDB_CMD_insertDepositDetails - { - /** - * The label of the source of the deposit to check - */ - const char *label_deposit; - unsigned int index_deposit; - } insert_deposit; - - /** - * Extra data requiered for the #PERF_TALER_MINTDB_CMD_GET_DEPOSIT command - */ - struct PERF_TALER_MINTDB_CMD_getDepositDetails - { - /** - * The label of the source of the deposit to check - */ - const char *label_deposit; - unsigned int index_deposit; - } get_deposit; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_SESSION command - */ - struct PERF_TALER_MINTDB_CMD_getRefreshSessionDetails - { - /** - * label of the source of the hash of the session - */ - const char *label_hash; - unsigned int index_hash; - } get_refresh_session; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_MELT command - */ - struct PERF_TALER_MINTDB_CMD_insertRefreshMeltDetails - { - /** - * The label of the hash of the refresh session - */ - const char *label_hash; - unsigned int index_hash; - - /** - * The label of the coin to melt - */ - const char *label_coin; - unsigned int index_coin; - } insert_refresh_melt; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_MELT command - */ - struct PERF_TALER_MINTDB_CMD_getRefreshMeltDetails - { - /** - * The label of the hash of the session - */ - const char *label_hash; - unsigned int index_hash; - } get_refresh_melt; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_ORDER command - */ - struct PERF_TALER_MINTDB_CMD_insertRefreshOrderDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - - /** - * The new coin denomination - */ - const char *label_denom; - unsigned int index_denom; - } insert_refresh_order; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_ORDER command - */ - struct PERF_TALER_MINTDB_CMD_getRefreshOrderDetails - { - /** - * The session hash - */ - const char *label_hash; - unsigned int index_hash; - - } get_refresh_order; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_COIN command - */ - struct PERF_TALER_MINTDB_CMD_insertRefreshCommitCoinDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - - } insert_refresh_commit_coin; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_COIN command - */ - struct PERF_TALER_MINTDB_CMD_getRefreshCommitCoinDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - - } get_refresh_commit_coin; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_COMMIT_LINK command - */ - struct PERF_TALER_MINTDB_CMD_insertRefreshCommitLinkDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - - } insert_refresh_commit_link; - - /** - * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_REFRESH_COMMIT_LINK command - */ - struct PERF_TALER_MINTDB_CMD_getRefreshCommitLinkDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - } get_refresh_commit_link; - - /** - * Data requiered for the #PERF_TALER_MINTDB_CMD_GET_MELT_COMMITMENT command - */ - struct PERF_TALER_MINTDB_CMD_getMeltCommitmentDaetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - } get_melt_commitment; - - /** - * Data requiered by the #PERF_TALER_MINTDB_CMD_INSERT_REFRESH_OUT command - */ - struct PERF_TALER_MINTDB_CMD_insertRefreshOutDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - } insert_refresh_out; - - /** - * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_LINK_DATA_LIST command - */ - struct PERF_TALER_MINTDB_CMD_getLinkDataListDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - } get_link_data_list; - - /** - * Data requiered by the #PERF_TALER_MINTDB_CMD_GET_TRANSFER command - */ - struct PERF_TALER_MINTDB_CMD_getTransferDetails - { - /** - * The refresh session hash - */ - const char *label_hash; - unsigned int index_hash; - } get_transfer; - -}; - - -/** - * Command to be interpreted. - */ -struct PERF_TALER_MINTDB_Cmd -{ - /** - * Type of the command - */ - enum PERF_TALER_MINTDB_CMD_Name command; - - /** - * Label to refer to the command - */ - const char *label; - - /** - * Command specific data - */ - union PERF_TALER_MINTDB_CMD_Details details; - - /** - * Data easily accessible - */ - struct PERF_TALER_MINTDB_Data exposed; -}; - - -/** - * Run a benchmark - * - * @param benchmark_name the name of the benchmark, displayed in the logs - * @param configuration_file path to the taler configuration file to use - * @param init the commands to use for the database initialisation, - * if #NULL the standard initialization is used - * @param benchmark the commands for the benchmark - * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure - */ -int -PERF_TALER_MINTDB_run_benchmark (const char *benchmark_name, - const char *configuration_file, - struct PERF_TALER_MINTDB_Cmd *init, - struct PERF_TALER_MINTDB_Cmd *benchmark); - - -/** - * Runs the command array @a cmd - * using @a db_plugin to connect to the database - * - * @param db_plugin the connection to the database - * @param cmd the commands to run - */ -int -PERF_TALER_MINTDB_interpret( - struct TALER_MINTDB_Plugin *db_plugin, - struct PERF_TALER_MINTDB_Cmd cmd[]); - - -/** - * Check if the given command array is syntaxicly correct - * This will check if the label are corrects but will not check if - * they are pointing to an apropriate command. - * - * @param cmd the command array to check - * @return #GNUNET_OK is @a cmd is correct; #GNUNET_SYSERR if it is'nt - */ -int -PERF_TALER_MINTDB_check (const struct PERF_TALER_MINTDB_Cmd *cmd); - -#endif diff --git a/src/mintdb/perf_taler_mintdb_values.h b/src/mintdb/perf_taler_mintdb_values.h deleted file mode 100644 index 35f87f5b0..000000000 --- a/src/mintdb/perf_taler_mintdb_values.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/perf_taler_mintdb_values.h - * @brief Values for tweaking the performance analysis - * @author Nicolas Fournier - */ -#ifndef __PERF_TALER_MINTDB__VALUES_H__ -#define __PERF_TALER_MINTDB__VALUES_H__ - - -#endif diff --git a/src/mintdb/plugin_mintdb_common.c b/src/mintdb/plugin_mintdb_common.c deleted file mode 100644 index 1f2fdc58b..000000000 --- a/src/mintdb/plugin_mintdb_common.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mintdb/plugin_mintdb_common.c - * @brief Functions shared across plugins, this file is meant to be - * included in each plugin. - * @author Christian Grothoff - */ - -/** - * Free memory associated with the given reserve history. - * - * @param cls the @e cls of this struct with the plugin-specific state (unused) - * @param rh history to free. - */ -static void -common_free_reserve_history (void *cls, - struct TALER_MINTDB_ReserveHistory *rh) -{ - struct TALER_MINTDB_BankTransfer *bt; - struct TALER_MINTDB_CollectableBlindcoin *cbc; - struct TALER_MINTDB_ReserveHistory *backref; - - while (NULL != rh) - { - switch(rh->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - bt = rh->details.bank; - if (NULL != bt->wire) - json_decref (bt->wire); - GNUNET_free (bt); - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - cbc = rh->details.withdraw; - GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key); - GNUNET_free (cbc); - break; - } - backref = rh; - rh = rh->next; - GNUNET_free (backref); - } -} - - -/** - * Free memory of the link data list. - * - * @param cls the @e cls of this struct with the plugin-specific state (unused) - * @param ldl link data list to release - */ -static void -common_free_link_data_list (void *cls, - struct TALER_MINTDB_LinkDataList *ldl) -{ - struct TALER_MINTDB_LinkDataList *next; - - while (NULL != ldl) - { - next = ldl->next; - GNUNET_free (ldl->link_data_enc); - GNUNET_free (ldl); - ldl = next; - } -} - - -/** - * Free linked list of transactions. - * - * @param cls the @e cls of this struct with the plugin-specific state (unused) - * @param list list to free - */ -static void -common_free_coin_transaction_list (void *cls, - struct TALER_MINTDB_TransactionList *list) -{ - struct TALER_MINTDB_TransactionList *next; - - while (NULL != list) - { - next = list->next; - - switch (list->type) - { - case TALER_MINTDB_TT_DEPOSIT: - json_decref (list->details.deposit->wire); - GNUNET_CRYPTO_rsa_public_key_free (list->details.deposit->coin.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (list->details.deposit->coin.denom_sig.rsa_signature); - GNUNET_free (list->details.deposit); - break; - case TALER_MINTDB_TT_REFRESH_MELT: - GNUNET_free (list->details.melt); - break; - } - GNUNET_free (list); - list = next; - } -} - - -/** - * Free melt commitment data. - * - * @param cls the @e cls of this struct with the plugin-specific state (unused) - * @param mc data structure to free - */ -static void -common_free_melt_commitment (void *cls, - struct TALER_MINTDB_MeltCommitment *mc) -{ - unsigned int i; - unsigned int k; - - if (NULL != mc->melts) - { - for (i=0;i<mc->num_oldcoins;i++) - { - GNUNET_CRYPTO_rsa_signature_free (mc->melts[i].coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (mc->melts[i].coin.denom_pub.rsa_public_key); - } - GNUNET_free (mc->melts); - } - if (NULL != mc->denom_pubs) - { - for (i=0;i<mc->num_newcoins;i++) - if (NULL != mc->denom_pubs[i].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (mc->denom_pubs[i].rsa_public_key); - GNUNET_free (mc->denom_pubs); - } - for (k=0;k<TALER_CNC_KAPPA;k++) - { - if (NULL != mc->commit_coins[k]) - { - for (i=0;i<mc->num_newcoins;i++) - { - GNUNET_free (mc->commit_coins[k][i].refresh_link); - GNUNET_free (mc->commit_coins[k][i].coin_ev); - } - GNUNET_free (mc->commit_coins[k]); - } - GNUNET_free_non_null (mc->commit_links[k]); - } - GNUNET_free (mc); -} - -/* end of plugin_mintdb_common.c */ diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c deleted file mode 100644 index 772b86e83..000000000 --- a/src/mintdb/plugin_mintdb_postgres.c +++ /dev/null @@ -1,4295 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file plugin_mintdb_postgres.c - * @brief Low-level (statement-level) Postgres database access for the mint - * @author Florian Dold - * @author Christian Grothoff - * @author Sree Harsha Totakura - */ -#include "platform.h" -#include "taler_pq_lib.h" -#include "taler_mintdb_plugin.h" -#include <pthread.h> -#include <libpq-fe.h> - -#include "plugin_mintdb_common.c" - -/** - * For testing / experiments, we set the Postgres schema to - * #TALER_TEMP_SCHEMA_NAME so we can easily purge everything - * associated with a test. We *also* should use the database - * "talercheck" instead of "taler" for testing, but we're doing - * both: better safe than sorry. - */ -#define TALER_TEMP_SCHEMA_NAME "taler_temporary" - -/** - * Log a query error. - * - * @param result PQ result object of the query that failed - */ -#define QUERY_ERR(result) \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result)) - - -/** - * Log a really unexpected PQ error. - * - * @param result PQ result object of the PQ operation that failed - */ -#define BREAK_DB_ERR(result) do { \ - GNUNET_break (0); \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ - } while (0) - - -/** - * Shorthand for exit jumps. Logs the current line number - * and jumps to the "EXITIF_exit" label. - * - * @param cond condition that must be TRUE to exit with an error - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Execute an SQL statement and log errors on failure. Must be - * run in a function that has an "SQLEXEC_fail" label to jump - * to in case the SQL statement failed. - * - * @param conn database connection - * @param sql SQL statement to run - */ -#define SQLEXEC_(conn, sql) \ - do { \ - PGresult *result = PQexec (conn, sql); \ - if (PGRES_COMMAND_OK != PQresultStatus (result)) \ - { \ - BREAK_DB_ERR (result); \ - PQclear (result); \ - goto SQLEXEC_fail; \ - } \ - PQclear (result); \ - } while (0) - - -/** - * Run an SQL statement, ignoring errors and clearing the result. - * - * @param conn database connection - * @param sql SQL statement to run - */ -#define SQLEXEC_IGNORE_ERROR_(conn, sql) \ - do { \ - PGresult *result = PQexec (conn, sql); \ - PQclear (result); \ - } while (0) - - -/** - * Handle for a database session (per-thread, for transactions). - */ -struct TALER_MINTDB_Session -{ - /** - * Postgres connection handle. - */ - PGconn *conn; -}; - - -/** - * Type of the "cls" argument given to each of the functions in - * our API. - */ -struct PostgresClosure -{ - - /** - * Thread-local database connection. - * Contains a pointer to `PGconn` or NULL. - */ - pthread_key_t db_conn_threadlocal; - - /** - * Database connection string, as read from - * the configuration. - */ - char *connection_cfg_str; -}; - - - -/** - * Set the given connection to use a temporary schema - * - * @param db the database connection - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error - */ -static int -set_temporary_schema (PGconn *db) -{ - SQLEXEC_(db, - "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";" - "SET search_path to " TALER_TEMP_SCHEMA_NAME ";"); - return GNUNET_OK; - SQLEXEC_fail: - return GNUNET_SYSERR; -} - - -/** - * Drop the temporary taler schema. This is only useful for testcases - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database session to use - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static int -postgres_drop_temporary (void *cls, - struct TALER_MINTDB_Session *session) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Dropping temporary tables\n"); - SQLEXEC_ (session->conn, - "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;"); - return GNUNET_OK; - SQLEXEC_fail: - return GNUNET_SYSERR; -} - - -/** - * Function called by libpq whenever it wants to log something. - * We already log whenever we care, so this function does nothing - * and merely exists to silence the libpq logging. - * - * @param arg NULL - * @param res information about some libpq event - */ -static void -pq_notice_receiver_cb (void *arg, - const PGresult *res) -{ - /* do nothing, intentionally */ -} - - -/** - * Function called by libpq whenever it wants to log something. - * We log those using the Taler logger. - * - * @param arg NULL - * @param message information about some libpq event - */ -static void -pq_notice_processor_cb (void *arg, - const char *message) -{ - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, - "pq", - "%s", - message); -} - - -/** - * Create the necessary tables if they are not present - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param temporary should we use a temporary schema - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static int -postgres_create_tables (void *cls, - int temporary) -{ - struct PostgresClosure *pc = cls; - PGconn *conn; - - conn = PQconnectdb (pc->connection_cfg_str); - if (CONNECTION_OK != PQstatus (conn)) - { - TALER_LOG_ERROR ("Database connection failed: %s\n", - PQerrorMessage (conn)); - PQfinish (conn); - return GNUNET_SYSERR; - } - PQsetNoticeReceiver (conn, - &pq_notice_receiver_cb, - NULL); - PQsetNoticeProcessor (conn, - &pq_notice_processor_cb, - NULL); - if ( (GNUNET_YES == temporary) && - (GNUNET_SYSERR == set_temporary_schema (conn))) - { - PQfinish (conn); - return GNUNET_SYSERR; - } -#define SQLEXEC(sql) SQLEXEC_(conn, sql); -#define SQLEXEC_INDEX(sql) SQLEXEC_IGNORE_ERROR_(conn, sql); - /* Denomination table for holding the publicly available information of - denominations keys. The denominations are to be referred to by using - foreign keys. The denominations are deleted by a housekeeping tool; - hence, do not use `ON DELETE CASCADE' on these rows in the tables - referencing these rows */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS denominations" - "(pub BYTEA PRIMARY KEY" - ",master_pub BYTEA NOT NULL CHECK (LENGTH(master_pub)=32)" - ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)" - ",valid_from INT8 NOT NULL" - ",expire_withdraw INT8 NOT NULL" - ",expire_spend INT8 NOT NULL" - ",expire_legal INT8 NOT NULL" - ",coin_val INT8 NOT NULL" /* value of this denom */ - ",coin_frac INT4 NOT NULL" /* fractional value of this denom */ - ",coin_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" /* assuming same currency for fees */ - ",fee_withdraw_val INT8 NOT NULL" - ",fee_withdraw_frac INT4 NOT NULL" - ",fee_withdraw_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",fee_deposit_val INT8 NOT NULL" - ",fee_deposit_frac INT4 NOT NULL" - ",fee_deposit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",fee_refresh_val INT8 NOT NULL" - ",fee_refresh_frac INT4 NOT NULL" - ",fee_refresh_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ")"); - /* reserves table is for summarization of a reserve. It is updated when new - funds are added and existing funds are withdrawn. The 'expiration_date' - can be used to eventually get rid of reserves that have not been used - for a very long time (either by refunding the owner or by greedily - grabbing the money, depending on the Mint's terms of service) */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves" - "(reserve_pub BYTEA PRIMARY KEY" - ",current_balance_val INT8 NOT NULL" - ",current_balance_frac INT4 NOT NULL" - ",current_balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",expiration_date INT8 NOT NULL" - ")"); - /* index on reserves table */ - SQLEXEC_INDEX ("CREATE INDEX reserves_reserve_pub_index ON " - "reserves (reserve_pub)"); - /* reserves_in table collects the transactions which transfer funds - into the reserve. The rows of this table correspond to each - incoming transaction. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in" - "(reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",balance_val INT8 NOT NULL" - ",balance_frac INT4 NOT NULL" - ",balance_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",details TEXT NOT NULL " - ",execution_date INT8 NOT NULL" - ",PRIMARY KEY (reserve_pub,details)" - ");"); - /* Create indices on reserves_in */ - SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_index" - " ON reserves_in (reserve_pub);"); - SQLEXEC_INDEX ("CREATE INDEX reserves_in_reserve_pub_details_index" - " ON reserves_in (reserve_pub,details);"); - SQLEXEC_INDEX ("CREATE INDEX execution_index" - " ON reserves_in (execution_date);"); - /* Table with the withdraw operations that have been performed on a reserve. - The 'h_blind_ev' is the hash of the blinded coin. It serves as a primary - key, as (broken) clients that use a non-random coin and blinding factor - should fail to even withdraw, as otherwise the coins will fail to deposit - (as they really must be unique). */ - SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves_out" - "(h_blind_ev BYTEA PRIMARY KEY" - ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" - ",denom_sig BYTEA NOT NULL" - ",reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32) REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)" - ",execution_date INT8 NOT NULL" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",withdraw_fee_val INT8 NOT NULL" - ",withdraw_fee_frac INT4 NOT NULL" - ",withdraw_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ");"); - /* Index blindcoins(reserve_pub) for get_reserves_out statement */ - SQLEXEC_INDEX ("CREATE INDEX reserves_out_reserve_pub_index ON" - " reserves_out (reserve_pub)"); - SQLEXEC_INDEX ("CREATE INDEX reserves_out_h_blind_ev_index ON " - "reserves_out (h_blind_ev)"); - /* Table with coins that have been (partially) spent, used to track - coin information only once. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins " - "(coin_pub BYTEA NOT NULL PRIMARY KEY" - ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" - ",denom_sig BYTEA NOT NULL" - ")"); - /** - * The DB will show negative values for some values of the following fields as - * we use them as 16 bit unsigned integers - * @a num_oldcoins - * @a num_newcoins - * Do not do arithmetic in SQL on these fields. - * NOTE: maybe we should instead forbid values >= 2^15 categorically? - */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions " - "(session_hash BYTEA PRIMARY KEY CHECK (LENGTH(session_hash)=64)" - ",num_oldcoins INT2 NOT NULL" - ",num_newcoins INT2 NOT NULL" - ",noreveal_index INT2 NOT NULL" - ")"); - /* Table with coins that have been melted. Gives the coin's public - key (coin_pub), the melting session, the index of this coin in that - session, the signature affirming the melting and the amount that - this coin contributed to the melting session. - */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melts " - "(coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)" - ",session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)" - ",oldcoin_index INT2 NOT NULL" - ",coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",melt_fee_val INT8 NOT NULL" - ",melt_fee_frac INT4 NOT NULL" - ",melt_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",PRIMARY KEY (session_hash, oldcoin_index)" /* a coin can be used only - once in a refresh session */ - ") "); - /* Table with information about the desired denominations to be created - during a refresh operation; contains the denomination key for each - of the coins (for a given refresh session) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order " - "(session_hash BYTEA NOT NULL CHECK (LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash)" - ",newcoin_index INT2 NOT NULL " - ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" - ",PRIMARY KEY (session_hash, newcoin_index)" - ")"); - - /* Table with the commitments for a refresh operation; includes - the session_hash for which this is the link information, the - oldcoin index and the cut-and-choose index (from 0 to #TALER_CNC_KAPPA-1), - as well as the actual link data (the transfer public key and the encrypted - link secret). - NOTE: We might want to simplify this and not have the oldcoin_index - and instead store all link secrets, one after the other, in one big BYTEA. - (#3814) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link " - "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)" - ",transfer_pub BYTEA NOT NULL CHECK(LENGTH(transfer_pub)=32)" - ",link_secret_enc BYTEA NOT NULL" - ",oldcoin_index INT2 NOT NULL" - ",cnc_index INT2 NOT NULL" - ")"); - /* Table with the commitments for the new coins that are to be created - during a melting session. Includes the session, the cut-and-choose - index and the index of the new coin, and the envelope of the new - coin to be signed, as well as the encrypted information about the - private key and the blinding factor for the coin (for verification - in case this cnc_index is chosen to be revealed) - - NOTE: We might want to simplify this and not have the - newcoin_index and instead store all coin_evs and - link_vector_encs, one after the other, in two big BYTEAs. - (#3815) */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin " - "(session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) " - ",cnc_index INT2 NOT NULL" - ",newcoin_index INT2 NOT NULL" - ",link_vector_enc BYTEA NOT NULL" - ",coin_ev BYTEA NOT NULL" - ")"); - /* Table with the signatures over coins generated during a refresh - operation. Needed to answer /refresh/link queries later. Stores - the coin signatures under the respective session hash and index. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_out " - "(session_hash BYTEA NOT NULL CHECK(LENGTH(session_hash)=64) REFERENCES refresh_sessions (session_hash) " - ",newcoin_index INT2 NOT NULL" - ",ev_sig BYTEA NOT NULL" - ")"); - /* This table contains the wire transfers the mint is supposed to - execute to transmit funds to the merchants (and manage refunds). */ - SQLEXEC("CREATE TABLE IF NOT EXISTS deposits " - "(serial_id BIGSERIAL PRIMARY KEY" - ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)" - ",denom_pub BYTEA NOT NULL REFERENCES denominations (pub)" - ",denom_sig BYTEA NOT NULL" - ",transaction_id INT8 NOT NULL" - ",amount_with_fee_val INT8 NOT NULL" - ",amount_with_fee_frac INT4 NOT NULL" - ",amount_with_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",deposit_fee_val INT8 NOT NULL" - ",deposit_fee_frac INT4 NOT NULL" - ",deposit_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",timestamp INT8 NOT NULL" - ",refund_deadline INT8 NOT NULL" - ",wire_deadline INT8 NOT NULL" - ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" - ",h_contract BYTEA NOT NULL CHECK (LENGTH(h_contract)=64)" - ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)" - ",coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)" - ",wire TEXT NOT NULL" - ",tiny BOOLEAN NOT NULL DEFAULT false" - ",done BOOLEAN NOT NULL DEFAULT false" - ")"); - /* Index for get_deposit statement on coin_pub, transaction_id and merchant_pub */ - SQLEXEC_INDEX("CREATE INDEX deposits_coin_pub_index " - "ON deposits(coin_pub, transaction_id, merchant_pub)"); - /* Table for the tracking API, mapping from wire transfer identifiers - to transactions and back */ - SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking " - "(h_contract BYTEA CHECK (LENGTH(h_contract)=64)" - ",h_wire BYTEA CHECK (LENGTH(h_wire)=64)" - ",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)" - ",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)" - ",transaction_id INT8 NOT NULL" - ",wtid_raw BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=" TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR ")" - ",execution_time INT8 NOT NULL" - ",coin_amount_val INT8 NOT NULL" - ",coin_amount_frac INT4 NOT NULL" - ",coin_amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ",coin_fee_val INT8 NOT NULL" - ",coin_fee_frac INT4 NOT NULL" - ",coin_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL" - ")"); - /* Index for lookup_transactions statement on wtid */ - SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index " - "ON aggregation_tracking(wtid_raw)"); - /* Index for lookup_deposit_wtid statement */ - SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_deposit_index " - "ON aggregation_tracking(coin_pub,h_contract,h_wire,transaction_id,merchant_pub)"); - - /* This table contains the pre-commit data for - wire transfers the mint is about to execute. */ - SQLEXEC("CREATE TABLE IF NOT EXISTS prewire " - "(serial_id BIGSERIAL PRIMARY KEY" - ",type TEXT NOT NULL" - ",finished BOOLEAN NOT NULL DEFAULT false" - ",buf BYTEA NOT NULL" - ")"); - /* Index for prepare_data_iterate statement */ - SQLEXEC_INDEX("CREATE INDEX prepare_iteration_index " - "ON prewire(type,finished)"); - - -#undef SQLEXEC -#undef SQLEXEC_INDEX - - PQfinish (conn); - return GNUNET_OK; - - SQLEXEC_fail: - PQfinish (conn); - return GNUNET_SYSERR; -} - - -/** - * Setup prepared statements. - * - * @param db_conn connection handle to initialize - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure - */ -static int -postgres_prepare (PGconn *db_conn) -{ - PGresult *result; - -#define PREPARE(name, sql, ...) \ - do { \ - result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ - if (PGRES_COMMAND_OK != PQresultStatus (result)) \ - { \ - BREAK_DB_ERR (result); \ - PQclear (result); result = NULL; \ - return GNUNET_SYSERR; \ - } \ - PQclear (result); result = NULL; \ - } while (0); - - /* Used in #postgres_insert_denomination_info() */ - PREPARE ("denomination_insert", - "INSERT INTO denominations " - "(pub" - ",master_pub" - ",master_sig" - ",valid_from" - ",expire_withdraw" - ",expire_spend" - ",expire_legal" - ",coin_val" /* value of this denom */ - ",coin_frac" /* fractional value of this denom */ - ",coin_curr" /* assuming same currency for fees */ - ",fee_withdraw_val" - ",fee_withdraw_frac" - ",fee_withdraw_curr" /* must match coin_curr */ - ",fee_deposit_val" - ",fee_deposit_frac" - ",fee_deposit_curr" /* must match coin_curr */ - ",fee_refresh_val" - ",fee_refresh_frac" - ",fee_refresh_curr" /* must match coin_curr */ - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," - " $11, $12, $13, $14, $15, $16, $17, $18, $19);", - 19, NULL); - - /* Used in #postgres_get_denomination_info() */ - PREPARE ("denomination_get", - "SELECT" - " master_pub" - ",master_sig" - ",valid_from" - ",expire_withdraw" - ",expire_spend" - ",expire_legal" - ",coin_val" /* value of this denom */ - ",coin_frac" /* fractional value of this denom */ - ",coin_curr" /* assuming same currency for fees */ - ",fee_withdraw_val" - ",fee_withdraw_frac" - ",fee_withdraw_curr" /* must match coin_curr */ - ",fee_deposit_val" - ",fee_deposit_frac" - ",fee_deposit_curr" /* must match coin_curr */ - ",fee_refresh_val" - ",fee_refresh_frac" - ",fee_refresh_curr" /* must match coin_curr */ - " FROM denominations" - " WHERE pub=$1;", - 1, NULL); - - /* Used in #postgres_reserve_get() */ - PREPARE ("reserve_get", - "SELECT" - " current_balance_val" - ",current_balance_frac" - ",current_balance_curr" - ",expiration_date" - " FROM reserves" - " WHERE reserve_pub=$1" - " LIMIT 1;", - 1, NULL); - - /* Used in #postgres_reserves_in_insert() when the reserve is new */ - PREPARE ("reserve_create", - "INSERT INTO reserves " - "(reserve_pub" - ",current_balance_val" - ",current_balance_frac" - ",current_balance_curr" - ",expiration_date" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5, NULL); - - /* Used in #postgres_reserves_update() when the reserve is updated */ - PREPARE ("reserve_update", - "UPDATE reserves" - " SET" - " expiration_date=$1 " - ",current_balance_val=$2 " - ",current_balance_frac=$3 " - "WHERE current_balance_curr=$4 AND reserve_pub=$5", - 5, NULL); - - /* Used in #postgres_reserves_in_insert() to store transaction details */ - PREPARE ("reserves_in_add_transaction", - "INSERT INTO reserves_in " - "(reserve_pub" - ",balance_val" - ",balance_frac" - ",balance_curr" - ",details" - ",execution_date" - ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6, NULL); - - /* Used in #postgres_get_reserve_history() to obtain inbound transactions - for a reserve */ - PREPARE ("reserves_in_get_transactions", - "SELECT" - " balance_val" - ",balance_frac" - ",balance_curr" - ",execution_date" - ",details" - " FROM reserves_in" - " WHERE reserve_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_withdraw_info() to store - the signature of a blinded coin with the blinded coin's - details before returning it during /reserve/withdraw. We store - the coin's denomination information (public key, signature) - and the blinded message as well as the reserve that the coin - is being withdrawn from and the signature of the message - authorizing the withdrawal. */ - PREPARE ("insert_withdraw_info", - "INSERT INTO reserves_out " - "(h_blind_ev" - ",denom_pub" - ",denom_sig" - ",reserve_pub" - ",reserve_sig" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",withdraw_fee_val" - ",withdraw_fee_frac" - ",withdraw_fee_curr" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);", - 12, NULL); - - /* Used in #postgres_get_withdraw_info() to - locate the response for a /reserve/withdraw request - using the hash of the blinded message. Used to - make sure /reserve/withdraw requests are idempotent. */ - PREPARE ("get_withdraw_info", - "SELECT" - " denom_pub" - ",denom_sig" - ",reserve_sig" - ",reserve_pub" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",withdraw_fee_val" - ",withdraw_fee_frac" - ",withdraw_fee_curr" - " FROM reserves_out" - " WHERE h_blind_ev=$1", - 1, NULL); - - /* Used during #postgres_get_reserve_history() to - obtain all of the /reserve/withdraw operations that - have been performed on a given reserve. (i.e. to - demonstrate double-spending) */ - PREPARE ("get_reserves_out", - "SELECT" - " h_blind_ev" - ",denom_pub" - ",denom_sig" - ",reserve_sig" - ",execution_date" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",withdraw_fee_val" - ",withdraw_fee_frac" - ",withdraw_fee_curr" - " FROM reserves_out" - " WHERE reserve_pub=$1;", - 1, NULL); - - /* Used in #postgres_get_refresh_session() to fetch - high-level information about a refresh session */ - PREPARE ("get_refresh_session", - "SELECT" - " num_oldcoins" - ",num_newcoins" - ",noreveal_index" - " FROM refresh_sessions " - " WHERE session_hash=$1 ", - 1, NULL); - - /* Used in #postgres_create_refresh_session() to store - high-level information about a refresh session */ - PREPARE ("insert_refresh_session", - "INSERT INTO refresh_sessions " - "(session_hash " - ",num_oldcoins " - ",num_newcoins " - ",noreveal_index " - ") VALUES " - "($1, $2, $3, $4);", - 4, NULL); - - /* Used in #postgres_get_known_coin() to fetch - the denomination public key and signature for - a coin known to the mint. */ - PREPARE ("get_known_coin", - "SELECT" - " denom_pub" - ",denom_sig" - " FROM known_coins" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_known_coin() to store - the denomination public key and signature for - a coin known to the mint. */ - PREPARE ("insert_known_coin", - "INSERT INTO known_coins " - "(coin_pub" - ",denom_pub" - ",denom_sig" - ") VALUES " - "($1,$2,$3);", - 3, NULL); - - /* Store information about the desired denominations for a - refresh operation, used in #postgres_insert_refresh_order() */ - PREPARE ("insert_refresh_order", - "INSERT INTO refresh_order " - "(newcoin_index " - ",session_hash " - ",denom_pub " - ") VALUES " - "($1, $2, $3);", - 3, NULL); - - /* Obtain information about the desired denominations for a - refresh operation, used in #postgres_get_refresh_order() */ - PREPARE ("get_refresh_order", - "SELECT denom_pub" - " FROM refresh_order" - " WHERE session_hash=$1 AND newcoin_index=$2", - 2, NULL); - - /* Used in #postgres_insert_refresh_melt to store information - about melted coins */ - PREPARE ("insert_refresh_melt", - "INSERT INTO refresh_melts " - "(coin_pub " - ",session_hash" - ",oldcoin_index " - ",coin_sig " - ",amount_with_fee_val " - ",amount_with_fee_frac " - ",amount_with_fee_curr " - ",melt_fee_val " - ",melt_fee_frac " - ",melt_fee_curr " - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);", - 10, NULL); - - /* Used in #postgres_get_refresh_melt to obtain information - about melted coins */ - PREPARE ("get_refresh_melt", - "SELECT" - " coin_pub" - ",coin_sig" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",melt_fee_val " - ",melt_fee_frac " - ",melt_fee_curr " - " FROM refresh_melts" - " WHERE session_hash=$1 AND oldcoin_index=$2", - 2, NULL); - - /* Query the 'refresh_melts' by coin public key */ - PREPARE ("get_refresh_melt_by_coin", - "SELECT" - " session_hash" - /* ",oldcoin_index" // not needed */ - ",coin_sig" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",melt_fee_val " - ",melt_fee_frac " - ",melt_fee_curr " - " FROM refresh_melts" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_refresh_commit_links() to - store commitments */ - PREPARE ("insert_refresh_commit_link", - "INSERT INTO refresh_commit_link " - "(session_hash" - ",transfer_pub" - ",cnc_index" - ",oldcoin_index" - ",link_secret_enc" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5, NULL); - - /* Used in #postgres_get_refresh_commit_links() to - retrieve original commitments during /refresh/reveal */ - PREPARE ("get_refresh_commit_link", - "SELECT" - " transfer_pub" - ",link_secret_enc" - " FROM refresh_commit_link" - " WHERE session_hash=$1 AND cnc_index=$2 AND oldcoin_index=$3", - 3, NULL); - - /* Used in #postgres_insert_refresh_commit_coins() to - store coin commitments. */ - PREPARE ("insert_refresh_commit_coin", - "INSERT INTO refresh_commit_coin " - "(session_hash" - ",cnc_index" - ",newcoin_index" - ",link_vector_enc" - ",coin_ev" - ") VALUES " - "($1, $2, $3, $4, $5);", - 5, NULL); - - /* Used in #postgres_get_refresh_commit_coins() to - retrieve the original coin envelopes, to either be - verified or signed. */ - PREPARE ("get_refresh_commit_coin", - "SELECT" - " link_vector_enc" - ",coin_ev" - " FROM refresh_commit_coin" - " WHERE session_hash=$1 AND cnc_index=$2 AND newcoin_index=$3", - 3, NULL); - - /* Store information about a /deposit the mint is to execute. - Used in #postgres_insert_deposit(). */ - PREPARE ("insert_deposit", - "INSERT INTO deposits " - "(coin_pub" - ",denom_pub" - ",denom_sig" - ",transaction_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",deposit_fee_val" - ",deposit_fee_frac" - ",deposit_fee_curr" - ",timestamp" - ",refund_deadline" - ",wire_deadline" - ",merchant_pub" - ",h_contract" - ",h_wire" - ",coin_sig" - ",wire" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," - " $11, $12, $13, $14, $15, $16, $17, $18);", - 18, NULL); - - /* Fetch an existing deposit request, used to ensure idempotency - during /deposit processing. Used in #postgres_have_deposit(). */ - PREPARE ("get_deposit", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",timestamp" - ",refund_deadline" - ",wire_deadline" - ",h_contract" - ",h_wire" - " FROM deposits" - " WHERE (" - " (coin_pub=$1) AND" - " (transaction_id=$2) AND" - " (merchant_pub=$3)" - " )", - 3, NULL); - - /* Fetch an existing deposit request. - Used in #postgres_wire_lookup_deposit_wtid(). */ - PREPARE ("get_deposit_for_wtid", - "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",deposit_fee_val" - ",deposit_fee_frac" - ",deposit_fee_curr" - ",wire_deadline" - " FROM deposits" - " WHERE (" - " (coin_pub=$1) AND" - " (transaction_id=$2) AND" - " (merchant_pub=$3) AND" - " (h_contract=$4) AND" - " (h_wire=$5)" - " )", - 5, NULL); - - /* Used in #postgres_get_ready_deposit() */ - PREPARE ("deposits_get_ready", - "SELECT" - " serial_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",deposit_fee_val" - ",deposit_fee_frac" - ",deposit_fee_curr" - ",wire_deadline" - ",transaction_id" - ",h_contract" - ",wire" - ",merchant_pub" - ",coin_pub" - " FROM deposits" - " WHERE" - " tiny=false AND" - " done=false" - " ORDER BY wire_deadline ASC" - " LIMIT 1;", - 0, NULL); - - /* Used in #postgres_iterate_matching_deposits() */ - PREPARE ("deposits_iterate_matching", - "SELECT" - " serial_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",deposit_fee_val" - ",deposit_fee_frac" - ",deposit_fee_curr" - ",wire_deadline" - ",transaction_id" - ",h_contract" - ",coin_pub" - " FROM deposits" - " WHERE" - " merchant_pub=$1 AND" - " h_wire=$2 AND" - " done=false" - " ORDER BY wire_deadline ASC" - " LIMIT $3", - 3, NULL); - - /* Used in #postgres_mark_deposit_tiny() */ - PREPARE ("mark_deposit_tiny", - "UPDATE deposits" - " SET tiny=true" - " WHERE serial_id=$1", - 1, NULL); - - /* Used in #postgres_mark_deposit_done() */ - PREPARE ("mark_deposit_done", - "UPDATE deposits" - " SET done=true" - " WHERE serial_id=$1", - 1, NULL); - - /* Used in #postgres_get_coin_transactions() to obtain information - about how a coin has been spend with /deposit requests. */ - PREPARE ("get_deposit_with_coin_pub", - "SELECT" - " denom_pub" - ",denom_sig" - ",transaction_id" - ",amount_with_fee_val" - ",amount_with_fee_frac" - ",amount_with_fee_curr" - ",deposit_fee_val" - ",deposit_fee_frac" - ",deposit_fee_curr" - ",timestamp" - ",refund_deadline" - ",merchant_pub" - ",h_contract" - ",h_wire" - ",wire" - ",coin_sig" - " FROM deposits" - " WHERE coin_pub=$1", - 1, NULL); - - /* Used in #postgres_insert_refresh_out() to store the - generated signature(s) for future requests, i.e. /refresh/link */ - PREPARE ("insert_refresh_out", - "INSERT INTO refresh_out " - "(session_hash" - ",newcoin_index" - ",ev_sig" - ") VALUES " - "($1, $2, $3)", - 3, NULL); - - /* Used in #postgres_get_link_data_list(). We use the session_hash - to obtain the "noreveal_index" for that session, and then select - the encrypted link vectors (link_vector_enc) and the - corresponding signatures (ev_sig) and the denomination keys from - the respective tables (namely refresh_melts and refresh_order) - using the session_hash as the primary filter (on join) and the - 'noreveal_index' to constrain the selection on the commitment. - We also want to get the triplet for each of the newcoins, so we - have another constraint to ensure we get each triplet with - matching "newcoin_index" values. NOTE: This may return many - results, both for different sessions and for the different coins - being minted in the refresh ops. NOTE: There may be more - efficient ways to express the same query. */ - PREPARE ("get_link", - "SELECT link_vector_enc,ev_sig,ro.denom_pub" - " FROM refresh_melts rm " - " JOIN refresh_order ro USING (session_hash)" - " JOIN refresh_commit_coin rcc USING (session_hash)" - " JOIN refresh_sessions rs USING (session_hash)" - " JOIN refresh_out rc USING (session_hash)" - " WHERE ro.session_hash=$1" - " AND ro.newcoin_index=rcc.newcoin_index" - " AND ro.newcoin_index=rc.newcoin_index" - " AND rcc.cnc_index=rs.noreveal_index", - 1, NULL); - - /* Used in #postgres_get_transfer(). Given the public key of a - melted coin, we obtain the corresponding encrypted link secret - and the transfer public key. This is done by first finding - the session_hash(es) of all sessions the coin was melted into, - and then constraining the result to the selected "noreveal_index" - and the transfer public key to the corresponding index of the - old coin. - NOTE: This may (in theory) return multiple results, one per session - that the old coin was melted into. */ - PREPARE ("get_transfer", - "SELECT transfer_pub,link_secret_enc,session_hash" - " FROM refresh_melts rm" - " JOIN refresh_commit_link rcl USING (session_hash)" - " JOIN refresh_sessions rs USING (session_hash)" - " WHERE rm.coin_pub=$1" - " AND rm.oldcoin_index = rcl.oldcoin_index" - " AND rcl.cnc_index=rs.noreveal_index", - 1, NULL); - - /* Used in #postgres_lookup_wire_transfer */ - PREPARE ("lookup_transactions", - "SELECT" - " h_contract" - ",h_wire" - ",coin_pub" - ",merchant_pub" - ",transaction_id" - ",execution_time" - ",coin_amount_val" - ",coin_amount_frac" - ",coin_amount_curr" - ",coin_fee_val" - ",coin_fee_frac" - ",coin_fee_curr" - " FROM aggregation_tracking" - " WHERE wtid_raw=$1", - 1, NULL); - - /* Used in #postgres_wire_lookup_deposit_wtid */ - PREPARE ("lookup_deposit_wtid", - "SELECT" - " wtid_raw" - ",execution_time" - ",coin_amount_val" - ",coin_amount_frac" - ",coin_amount_curr" - ",coin_fee_val" - ",coin_fee_frac" - ",coin_fee_curr" - " FROM aggregation_tracking" - " WHERE" - " coin_pub=$1 AND" - " h_contract=$2 AND" - " h_wire=$3 AND" - " transaction_id=$4 AND" - " merchant_pub=$5", - 5, NULL); - - /* Used in #postgres_insert_aggregation_tracking */ - PREPARE ("insert_aggregation_tracking", - "INSERT INTO aggregation_tracking " - "(h_contract" - ",h_wire" - ",coin_pub" - ",merchant_pub" - ",transaction_id" - ",wtid_raw" - ",execution_time" - ",coin_amount_val" - ",coin_amount_frac" - ",coin_amount_curr" - ",coin_fee_val" - ",coin_fee_frac" - ",coin_fee_curr" - ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", - 13, NULL); - - - /* Used in #postgres_wire_prepare_data_insert() to store - wire transfer information before actually committing it with the bank */ - PREPARE ("wire_prepare_data_insert", - "INSERT INTO prewire " - "(type" - ",buf" - ") VALUES " - "($1, $2)", - 2, NULL); - - /* Used in #postgres_wire_prepare_data_mark_finished() */ - PREPARE ("wire_prepare_data_mark_done", - "UPDATE prewire" - " SET finished=true" - " WHERE serial_id=$1", - 1, NULL); - - /* Used in #postgres_wire_prepare_data_get() */ - PREPARE ("wire_prepare_data_get", - "SELECT" - " serial_id" - ",buf" - " FROM prewire" - " WHERE" - " type=$1 AND" - " finished=false" - " ORDER BY serial_id ASC" - " LIMIT 1", - 1, NULL); - - return GNUNET_OK; -#undef PREPARE -} - - -/** - * Close thread-local database connection when a thread is destroyed. - * - * @param cls closure we get from pthreads (the db handle) - */ -static void -db_conn_destroy (void *cls) -{ - struct TALER_MINTDB_Session *session = cls; - PGconn *db_conn = session->conn; - - if (NULL != db_conn) - PQfinish (db_conn); - GNUNET_free (session); -} - - -/** - * Get the thread-local database-handle. - * Connect to the db if the connection does not exist yet. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the - * database default one - * @return the database connection, or NULL on error - */ -static struct TALER_MINTDB_Session * -postgres_get_session (void *cls, - int temporary) -{ - struct PostgresClosure *pc = cls; - PGconn *db_conn; - struct TALER_MINTDB_Session *session; - - if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal))) - return session; - db_conn = PQconnectdb (pc->connection_cfg_str); - if (CONNECTION_OK != - PQstatus (db_conn)) - { - TALER_LOG_ERROR ("Database connection failed: %s\n", - PQerrorMessage (db_conn)); - GNUNET_break (0); - return NULL; - } - PQsetNoticeReceiver (db_conn, - &pq_notice_receiver_cb, - NULL); - PQsetNoticeProcessor (db_conn, - &pq_notice_processor_cb, - NULL); - if ( (GNUNET_YES == temporary) && - (GNUNET_SYSERR == set_temporary_schema(db_conn)) ) - { - GNUNET_break (0); - return NULL; - } - if (GNUNET_OK != - postgres_prepare (db_conn)) - { - GNUNET_break (0); - return NULL; - } - session = GNUNET_new (struct TALER_MINTDB_Session); - session->conn = db_conn; - if (0 != pthread_setspecific (pc->db_conn_threadlocal, - session)) - { - GNUNET_break (0); - PQfinish (db_conn); - GNUNET_free (session); - return NULL; - } - return session; -} - - -/** - * Start a transaction. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection - * @return #GNUNET_OK on success - */ -static int -postgres_start (void *cls, - struct TALER_MINTDB_Session *session) -{ - PGresult *result; - - result = PQexec (session->conn, - "BEGIN"); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - TALER_LOG_ERROR ("Failed to start transaction: %s\n", - PQresultErrorMessage (result)); - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Roll back the current transaction of a database connection. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection - * @return #GNUNET_OK on success - */ -static void -postgres_rollback (void *cls, - struct TALER_MINTDB_Session *session) -{ - PGresult *result; - - result = PQexec (session->conn, - "ROLLBACK"); - GNUNET_break (PGRES_COMMAND_OK == - PQresultStatus (result)); - PQclear (result); -} - - -/** - * Commit the current transaction of a database connection. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection - * @return #GNUNET_OK on success - */ -static int -postgres_commit (void *cls, - struct TALER_MINTDB_Session *session) -{ - PGresult *result; - - result = PQexec (session->conn, - "COMMIT"); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - const char *sqlstate; - - sqlstate = PQresultErrorField (result, - PG_DIAG_SQLSTATE); - if (NULL == sqlstate) - { - /* very unexpected... */ - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - /* 40P01: deadlock, 40001: serialization failure */ - if ( (0 == strcmp (sqlstate, - "40P01")) || - (0 == strcmp (sqlstate, - "40001")) ) - { - /* These two can be retried and have a fair chance of working - the next time */ - PQclear (result); - return GNUNET_NO; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database commit failure: %s\n", - sqlstate); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Insert a denomination key's public information into the database for - * reference by auditors and other consistency checks. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @param denom_pub the public key used for signing coins of this denomination - * @param issue issuing information with value, fees and other info about the coin - * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure - */ -static int -postgres_insert_denomination_info (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_MINTDB_DenominationKeyInformationP *issue) -{ - PGresult *result; - int ret; - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key), - GNUNET_PQ_query_param_auto_from_type (&issue->properties.master), - GNUNET_PQ_query_param_auto_from_type (&issue->signature), - GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.start), - GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_withdraw), - GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_spend), - GNUNET_PQ_query_param_absolute_time_nbo (&issue->properties.expire_legal), - TALER_PQ_query_param_amount_nbo (&issue->properties.value), - TALER_PQ_query_param_amount_nbo (&issue->properties.fee_withdraw), - TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit), - TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh), - GNUNET_PQ_query_param_end - }; - /* check fees match coin currency */ - GNUNET_assert (GNUNET_YES == - TALER_amount_cmp_currency_nbo (&issue->properties.value, - &issue->properties.fee_withdraw)); - GNUNET_assert (GNUNET_YES == - TALER_amount_cmp_currency_nbo (&issue->properties.value, - &issue->properties.fee_deposit)); - GNUNET_assert (GNUNET_YES == - TALER_amount_cmp_currency_nbo (&issue->properties.value, - &issue->properties.fee_refresh)); - - result = GNUNET_PQ_exec_prepared (session->conn, - "denomination_insert", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - ret = GNUNET_SYSERR; - BREAK_DB_ERR (result); - } - else - { - ret = GNUNET_OK; - } - PQclear (result); - return ret; -} - - -/** - * Fetch information about a denomination key. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to use - * @param denom_pub the public key used for signing coins of this denomination - * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL - * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure - */ -static int -postgres_get_denomination_info (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_DenominationPublicKey *denom_pub, - struct TALER_MINTDB_DenominationKeyInformationP *issue) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_rsa_public_key (denom_pub->rsa_public_key), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "denomination_get", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - if (1 != PQntuples (result)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - if (NULL == issue) - { - PQclear (result); - return GNUNET_OK; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("master_pub", - &issue->properties.master), - GNUNET_PQ_result_spec_auto_from_type ("master_sig", - &issue->signature), - GNUNET_PQ_result_spec_absolute_time_nbo ("valid_from", - &issue->properties.start), - GNUNET_PQ_result_spec_absolute_time_nbo ("expire_withdraw", - &issue->properties.expire_withdraw), - GNUNET_PQ_result_spec_absolute_time_nbo ("expire_spend", - &issue->properties.expire_spend), - GNUNET_PQ_result_spec_absolute_time_nbo ("expire_legal", - &issue->properties.expire_legal), - TALER_PQ_result_spec_amount_nbo ("coin", - &issue->properties.value), - TALER_PQ_result_spec_amount_nbo ("fee_withdraw", - &issue->properties.fee_withdraw), - TALER_PQ_result_spec_amount_nbo ("fee_deposit", - &issue->properties.fee_deposit), - TALER_PQ_result_spec_amount_nbo ("fee_refresh", - &issue->properties.fee_refresh), - GNUNET_PQ_result_spec_end - }; - - EXITIF (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - 0)); - } - PQclear (result); - return GNUNET_OK; - - EXITIF_exit: - PQclear (result); - return GNUNET_SYSERR; -} - - -/** - * Get the summary of a reserve. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection handle - * @param[in,out] reserve the reserve data. The public key of the reserve should be - * set in this structure; it is used to query the database. The balance - * and expiration are then filled accordingly. - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static int -postgres_reserve_get (void *cls, - struct TALER_MINTDB_Session *session, - struct TALER_MINTDB_Reserve *reserve) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type(&reserve->pub), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "reserve_get", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_amount("current_balance", &reserve->balance), - GNUNET_PQ_result_spec_absolute_time("expiration_date", &reserve->expiry), - GNUNET_PQ_result_spec_end - }; - - EXITIF (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - 0)); - } - PQclear (result); - return GNUNET_OK; - - EXITIF_exit: - PQclear (result); - return GNUNET_SYSERR; -} - - -/** - * Updates a reserve with the data from the given reserve structure. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection - * @param reserve the reserve structure whose data will be used to update the - * corresponding record in the database. - * @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error - */ -static int -reserves_update (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_Reserve *reserve) -{ - PGresult *result; - int ret; - - if (NULL == reserve) - return GNUNET_SYSERR; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&reserve->expiry), - TALER_PQ_query_param_amount (&reserve->balance), - GNUNET_PQ_query_param_auto_from_type (&reserve->pub), - GNUNET_PQ_query_param_end - }; - result = GNUNET_PQ_exec_prepared (session->conn, - "reserve_update", - params); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - QUERY_ERR (result); - ret = GNUNET_SYSERR; - } - else - { - ret = GNUNET_OK; - } - PQclear (result); - return ret; -} - - -/** - * Insert an incoming transaction into reserves. New reserves are also created - * through this function. Note that this API call starts (and stops) its - * own transaction scope (so the application must not do so). - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session the database connection handle - * @param reserve_pub public key of the reserve - * @param balance the amount that has to be added to the reserve - * @param execution_time when was the amount added - * @param details bank transaction details justifying the increment, - * must be unique for each incoming transaction - * @return #GNUNET_OK upon success; #GNUNET_NO if the given - * @a details are already known for this @a reserve_pub, - * #GNUNET_SYSERR upon failures (DB error, incompatible currency) - */ -static int -postgres_reserves_in_insert (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *balance, - struct GNUNET_TIME_Absolute execution_time, - const json_t *details) -{ - PGresult *result; - int reserve_exists; - struct TALER_MINTDB_Reserve reserve; - struct GNUNET_TIME_Absolute expiry; - - if (GNUNET_OK != postgres_start (cls, - session)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - reserve.pub = *reserve_pub; - reserve_exists = postgres_reserve_get (cls, - session, - &reserve); - if (GNUNET_SYSERR == reserve_exists) - { - GNUNET_break (0); - goto rollback; - } - expiry = GNUNET_TIME_absolute_add (execution_time, - TALER_IDLE_RESERVE_EXPIRATION_TIME); - if (GNUNET_NO == reserve_exists) - { - /* New reserve, create balance for the first time; we do this - before adding the actual transaction to "reserves_in", as - for a new reserve it can't be a duplicate 'add' operation, - and as the 'add' operation may need the reserve entry - as a foreign key. */ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - TALER_PQ_query_param_amount (balance), - GNUNET_PQ_query_param_absolute_time (&expiry), - GNUNET_PQ_query_param_end - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Reserve does not exist; creating a new one\n"); - result = GNUNET_PQ_exec_prepared (session->conn, - "reserve_create", - params); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - QUERY_ERR (result); - PQclear (result); - goto rollback; - } - PQclear (result); - } - /* Create new incoming transaction, SQL "primary key" logic - is used to guard against duplicates. If a duplicate is - detected, we rollback (which really shouldn't undo - anything) and return #GNUNET_NO to indicate that this failure - is kind-of harmless (already executed). */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&reserve.pub), - TALER_PQ_query_param_amount (balance), - TALER_PQ_query_param_json (details), - GNUNET_PQ_query_param_absolute_time (&execution_time), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "reserves_in_add_transaction", - params); - } - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - const char *efield; - - efield = PQresultErrorField (result, - PG_DIAG_SQLSTATE); - if ( (PGRES_FATAL_ERROR == PQresultStatus(result)) && - (NULL != strstr ("23505", /* unique violation */ - efield)) ) - { - /* This means we had the same reserve/justification/details - before */ - PQclear (result); - postgres_rollback (cls, - session); - return GNUNET_NO; - } - QUERY_ERR (result); - PQclear (result); - goto rollback; - } - PQclear (result); - - if (GNUNET_YES == reserve_exists) - { - /* If the reserve already existed, we need to still update the - balance; we do this after checking for duplication, as - otherwise we might have to actually pay the cost to roll this - back for duplicate transactions; like this, we should virtually - never actually have to rollback anything. */ - struct TALER_MINTDB_Reserve updated_reserve; - - updated_reserve.pub = reserve.pub; - if (GNUNET_OK != - TALER_amount_add (&updated_reserve.balance, - &reserve.balance, - balance)) - { - /* currency overflow or incompatible currency */ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Attempt to deposit incompatible amount into reserve\n"); - goto rollback; - } - updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, - reserve.expiry); - if (GNUNET_OK != reserves_update (cls, - session, - &updated_reserve)) - goto rollback; - } - if (GNUNET_OK != postgres_commit (cls, - session)) - return GNUNET_SYSERR; - return GNUNET_OK; - - rollback: - postgres_rollback (cls, - session); - return GNUNET_SYSERR; -} - - -/** - * Locate the response for a /reserve/withdraw request under the - * key of the hash of the blinded message. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param h_blind hash of the blinded coin to be signed (will match - * `h_coin_envelope` in the @a collectable to be returned) - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ -static int -postgres_get_withdraw_info (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_blind, - struct TALER_MINTDB_CollectableBlindcoin *collectable) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (h_blind), - GNUNET_PQ_query_param_end - }; - int ret; - - ret = GNUNET_SYSERR; - result = GNUNET_PQ_exec_prepared (session->conn, - "get_withdraw_info", - params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - if (0 == PQntuples (result)) - { - ret = GNUNET_NO; - goto cleanup; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &collectable->denom_pub.rsa_public_key), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &collectable->sig.rsa_signature), - GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", - &collectable->reserve_sig), - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - &collectable->reserve_pub), - TALER_PQ_result_spec_amount ("amount_with_fee", - &collectable->amount_with_fee), - TALER_PQ_result_spec_amount ("withdraw_fee", - &collectable->withdraw_fee), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - goto cleanup; - } - } - collectable->h_coin_envelope = *h_blind; - ret = GNUNET_YES; - - cleanup: - PQclear (result); - return ret; -} - - -/** - * Store collectable bit coin under the corresponding - * hash of the blinded message. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ -static int -postgres_insert_withdraw_info (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_CollectableBlindcoin *collectable) -{ - PGresult *result; - struct TALER_MINTDB_Reserve reserve; - int ret = GNUNET_SYSERR; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute expiry; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope), - GNUNET_PQ_query_param_rsa_public_key (collectable->denom_pub.rsa_public_key), - GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature), - GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub), - GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig), - GNUNET_PQ_query_param_absolute_time (&now), - TALER_PQ_query_param_amount (&collectable->amount_with_fee), - TALER_PQ_query_param_amount (&collectable->withdraw_fee), - GNUNET_PQ_query_param_end - }; - - now = GNUNET_TIME_absolute_get (); - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_withdraw_info", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - reserve.pub = collectable->reserve_pub; - if (GNUNET_OK != postgres_reserve_get (cls, - session, - &reserve)) - { - /* Should have been checked before we got here... */ - GNUNET_break (0); - goto cleanup; - } - if (GNUNET_SYSERR == - TALER_amount_subtract (&reserve.balance, - &reserve.balance, - &collectable->amount_with_fee)) - { - /* Should have been checked before we got here... */ - GNUNET_break (0); - goto cleanup; - } - expiry = GNUNET_TIME_absolute_add (now, - TALER_IDLE_RESERVE_EXPIRATION_TIME); - reserve.expiry = GNUNET_TIME_absolute_max (expiry, - reserve.expiry); - if (GNUNET_OK != reserves_update (cls, - session, - &reserve)) - { - GNUNET_break (0); - goto cleanup; - } - ret = GNUNET_OK; - cleanup: - PQclear (result); - return ret; -} - - -/** - * Get all of the transaction history associated with the specified - * reserve. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session connection to use - * @param reserve_pub public key of the reserve - * @return known transaction history (NULL if reserve is unknown) - */ -static struct TALER_MINTDB_ReserveHistory * -postgres_get_reserve_history (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - PGresult *result; - struct TALER_MINTDB_ReserveHistory *rh; - struct TALER_MINTDB_ReserveHistory *rh_tail; - int rows; - int ret; - - rh = NULL; - rh_tail = NULL; - ret = GNUNET_SYSERR; - { - struct TALER_MINTDB_BankTransfer *bt; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "reserves_in_get_transactions", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - if (0 == (rows = PQntuples (result))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asked to fetch history for an unknown reserve.\n"); - goto cleanup; - } - while (0 < rows) - { - bt = GNUNET_new (struct TALER_MINTDB_BankTransfer); - { - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_amount ("balance", - &bt->amount), - GNUNET_PQ_result_spec_absolute_time ("execution_date", - &bt->execution_date), - TALER_PQ_result_spec_json ("details", - &bt->wire), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_YES != - GNUNET_PQ_extract_result (result, rs, --rows)) - { - GNUNET_break (0); - GNUNET_free (bt); - PQclear (result); - goto cleanup; - } - } - bt->reserve_pub = *reserve_pub; - if (NULL != rh_tail) - { - rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory); - rh_tail = rh_tail->next; - } - else - { - rh_tail = GNUNET_new (struct TALER_MINTDB_ReserveHistory); - rh = rh_tail; - } - rh_tail->type = TALER_MINTDB_RO_BANK_TO_MINT; - rh_tail->details.bank = bt; - } - PQclear (result); - } - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserve_pub), - GNUNET_PQ_query_param_end - }; - - GNUNET_assert (NULL != rh); - GNUNET_assert (NULL != rh_tail); - GNUNET_assert (NULL == rh_tail->next); - result = GNUNET_PQ_exec_prepared (session->conn, - "get_reserves_out", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - PQclear (result); - goto cleanup; - } - rows = PQntuples (result); - while (0 < rows) - { - struct TALER_MINTDB_CollectableBlindcoin *cbc; - - cbc = GNUNET_new (struct TALER_MINTDB_CollectableBlindcoin); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev", - &cbc->h_coin_envelope), - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &cbc->denom_pub.rsa_public_key), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &cbc->sig.rsa_signature), - GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", - &cbc->reserve_sig), - TALER_PQ_result_spec_amount ("amount_with_fee", - &cbc->amount_with_fee), - TALER_PQ_result_spec_amount ("withdraw_fee", - &cbc->withdraw_fee), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_YES != - GNUNET_PQ_extract_result (result, rs, --rows)) - { - GNUNET_break (0); - GNUNET_free (cbc); - PQclear (result); - goto cleanup; - } - cbc->reserve_pub = *reserve_pub; - } - rh_tail->next = GNUNET_new (struct TALER_MINTDB_ReserveHistory); - rh_tail = rh_tail->next; - rh_tail->type = TALER_MINTDB_RO_WITHDRAW_COIN; - rh_tail->details.withdraw = cbc; - } - ret = GNUNET_OK; - PQclear (result); - } - cleanup: - if (GNUNET_SYSERR == ret) - { - common_free_reserve_history (cls, - rh); - rh = NULL; - } - return rh; -} - - -/** - * Check if we have the specified deposit already in the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param deposit deposit to search for - * @return #GNUNET_YES if we know this operation, - * #GNUNET_NO if this exact deposit is unknown to us - * #GNUNET_SYSERR on DB error - */ -static int -postgres_have_deposit (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_Deposit *deposit) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub), - GNUNET_PQ_query_param_uint64 (&deposit->transaction_id), - GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_deposit", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - - /* Now we check that the other information in @a deposit - also matches, and if not report inconsistencies. */ - { - struct TALER_MINTDB_Deposit deposit2; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_amount ("amount_with_fee", - &deposit2.amount_with_fee), - GNUNET_PQ_result_spec_absolute_time ("timestamp", - &deposit2.timestamp), - GNUNET_PQ_result_spec_absolute_time ("refund_deadline", - &deposit2.refund_deadline), - GNUNET_PQ_result_spec_absolute_time ("wire_deadline", - &deposit2.wire_deadline), - GNUNET_PQ_result_spec_auto_from_type ("h_contract", - &deposit2.h_contract), - GNUNET_PQ_result_spec_auto_from_type ("h_wire", - &deposit2.h_wire), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee, - &deposit2.amount_with_fee)) || - (deposit->timestamp.abs_value_us != - deposit2.timestamp.abs_value_us) || - (deposit->refund_deadline.abs_value_us != - deposit2.refund_deadline.abs_value_us) || - (0 != memcmp (&deposit->h_contract, - &deposit2.h_contract, - sizeof (struct GNUNET_HashCode))) || - (0 != memcmp (&deposit->h_wire, - &deposit2.h_wire, - sizeof (struct GNUNET_HashCode))) ) - { - /* Inconsistencies detected! Does not match! (We might want to - expand the API with a 'get_deposit' function to return the - original transaction details to be used for an error message - in the future!) #3838 */ - PQclear (result); - return GNUNET_NO; - } - } - PQclear (result); - return GNUNET_YES; -} - - -/** - * Mark a deposit as tiny, thereby declaring that it cannot be - * executed by itself and should no longer be returned by - * @e iterate_ready_deposits() - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_rowid identifies the deposit row to modify - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -postgres_mark_deposit_tiny (void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid) -{ - uint64_t serial_id = rowid; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&serial_id), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "mark_deposit_tiny", - params); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Mark a deposit as done, thereby declaring that it cannot be - * executed at all anymore, and should no longer be returned by - * @e iterate_ready_deposits() or @e iterate_matching_deposits(). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_rowid identifies the deposit row to modify - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -postgres_mark_deposit_done (void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid) -{ - uint64_t serial_id = rowid; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&serial_id), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "mark_deposit_done", - params); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Obtain information about deposits that are ready to be executed. - * Such deposits must not be marked as "tiny" or "done", and the - * execution time must be in the past. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param deposit_cb function to call for ONE such deposit - * @param deposit_cb_cls closure for @a deposit_cb - * @return number of rows processed, 0 if none exist, - * #GNUNET_SYSERR on error - */ -static int -postgres_get_ready_deposit (void *cls, - struct TALER_MINTDB_Session *session, - TALER_MINTDB_DepositIterator deposit_cb, - void *deposit_cb_cls) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_end - }; - PGresult *result; - unsigned int n; - int ret; - - result = GNUNET_PQ_exec_prepared (session->conn, - "deposits_get_ready", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == (n = PQntuples (result))) - { - PQclear (result); - return 0; - } - GNUNET_break (1 == n); - { - struct TALER_Amount amount_with_fee; - struct TALER_Amount deposit_fee; - struct GNUNET_TIME_Absolute wire_deadline; - struct GNUNET_HashCode h_contract; - struct TALER_MerchantPublicKeyP merchant_pub; - struct TALER_CoinSpendPublicKeyP coin_pub; - uint64_t transaction_id; - uint64_t serial_id; - json_t *wire; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("serial_id", - &serial_id), - GNUNET_PQ_result_spec_uint64 ("transaction_id", - &transaction_id), - TALER_PQ_result_spec_amount ("amount_with_fee", - &amount_with_fee), - TALER_PQ_result_spec_amount ("deposit_fee", - &deposit_fee), - GNUNET_PQ_result_spec_absolute_time ("wire_deadline", - &wire_deadline), - GNUNET_PQ_result_spec_auto_from_type ("h_contract", - &h_contract), - GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", - &merchant_pub), - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", - &coin_pub), - TALER_PQ_result_spec_json ("wire", - &wire), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - ret = deposit_cb (deposit_cb_cls, - serial_id, - &merchant_pub, - &coin_pub, - &amount_with_fee, - &deposit_fee, - transaction_id, - &h_contract, - wire_deadline, - wire); - GNUNET_PQ_cleanup_result (rs); - PQclear (result); - } - return (GNUNET_OK == ret) ? 1 : 0; -} - - -/** - * Obtain information about other pending deposits for the same - * destination. Those deposits must not already be "done". - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session connection to the database - * @param h_wire destination of the wire transfer - * @param merchant_pub public key of the merchant - * @param deposit_cb function to call for each deposit - * @param deposit_cb_cls closure for @a deposit_cb - * @param limit maximum number of matching deposits to return - * @return number of rows processed, 0 if none exist, - * #GNUNET_SYSERR on error - */ -static int -postgres_iterate_matching_deposits (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_wire, - const struct TALER_MerchantPublicKeyP *merchant_pub, - TALER_MINTDB_DepositIterator deposit_cb, - void *deposit_cb_cls, - uint32_t limit) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (merchant_pub), - GNUNET_PQ_query_param_auto_from_type (h_wire), - GNUNET_PQ_query_param_uint32 (&limit), - GNUNET_PQ_query_param_end - }; - PGresult *result; - unsigned int i; - unsigned int n; - - result = GNUNET_PQ_exec_prepared (session->conn, - "deposits_iterate_matching", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == (n = PQntuples (result))) - { - PQclear (result); - return 0; - } - if (n > limit) - n = limit; - for (i=0;i<n;i++) - { - struct TALER_Amount amount_with_fee; - struct TALER_Amount deposit_fee; - struct GNUNET_TIME_Absolute wire_deadline; - struct GNUNET_HashCode h_contract; - struct TALER_MerchantPublicKeyP merchant_pub; - struct TALER_CoinSpendPublicKeyP coin_pub; - uint64_t transaction_id; - uint64_t serial_id; - int ret; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("serial_id", - &serial_id), - GNUNET_PQ_result_spec_uint64 ("transaction_id", - &transaction_id), - TALER_PQ_result_spec_amount ("amount_with_fee", - &amount_with_fee), - TALER_PQ_result_spec_amount ("deposit_fee", - &deposit_fee), - GNUNET_PQ_result_spec_absolute_time ("wire_deadline", - &wire_deadline), - GNUNET_PQ_result_spec_auto_from_type ("h_contract", - &h_contract), - GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", - &merchant_pub), - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", - &coin_pub), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, i)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - ret = deposit_cb (deposit_cb_cls, - serial_id, - &merchant_pub, - &coin_pub, - &amount_with_fee, - &deposit_fee, - transaction_id, - &h_contract, - wire_deadline, - NULL); - GNUNET_PQ_cleanup_result (rs); - PQclear (result); - if (GNUNET_OK != ret) - break; - } - return i; -} - - -/** - * Insert information about deposited coin into the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session connection to the database - * @param deposit deposit information to store - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -postgres_insert_deposit (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_MINTDB_Deposit *deposit) -{ - PGresult *result; - int ret; - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub), - GNUNET_PQ_query_param_rsa_public_key (deposit->coin.denom_pub.rsa_public_key), - GNUNET_PQ_query_param_rsa_signature (deposit->coin.denom_sig.rsa_signature), - GNUNET_PQ_query_param_uint64 (&deposit->transaction_id), - TALER_PQ_query_param_amount (&deposit->amount_with_fee), - TALER_PQ_query_param_amount (&deposit->deposit_fee), - GNUNET_PQ_query_param_absolute_time (&deposit->timestamp), - GNUNET_PQ_query_param_absolute_time (&deposit->refund_deadline), - GNUNET_PQ_query_param_absolute_time (&deposit->wire_deadline), - GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub), - GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract), - GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire), - GNUNET_PQ_query_param_auto_from_type (&deposit->csig), - TALER_PQ_query_param_json (deposit->wire), - GNUNET_PQ_query_param_end - }; - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_deposit", - params); - } - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - ret = GNUNET_SYSERR; - } - else - { - ret = GNUNET_OK; - } - PQclear (result); - return ret; -} - - -/** - * Lookup refresh session data under the given @a session_hash. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database handle to use - * @param session_hash hash over the melt to use to locate the session - * @param[out] refresh_session where to store the result, can be NULL - * to just check if the session exists - * @return #GNUNET_YES on success, - * #GNUNET_NO if not found, - * #GNUNET_SYSERR on DB failure - */ -static int -postgres_get_refresh_session (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - struct TALER_MINTDB_RefreshSession *refresh_session) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_session", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - GNUNET_assert (1 == PQntuples (result)); - if (NULL == refresh_session) - { - /* We're done if the caller is only interested in whether the - * session exists or not */ - PQclear (result); - return GNUNET_YES; - } - memset (refresh_session, - 0, - sizeof (struct TALER_MINTDB_RefreshSession)); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint16 ("num_oldcoins", - &refresh_session->num_oldcoins), - GNUNET_PQ_result_spec_uint16 ("num_newcoins", - &refresh_session->num_newcoins), - GNUNET_PQ_result_spec_uint16 ("noreveal_index", - &refresh_session->noreveal_index), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - } - PQclear (result); - return GNUNET_YES; -} - - -/** - * Store new refresh session data under the given @a session_hash. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database handle to use - * @param session_hash hash over the melt to use to locate the session - * @param refresh_session session data to store - * @return #GNUNET_YES on success, - * #GNUNET_SYSERR on DB failure - */ -static int -postgres_create_refresh_session (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - const struct TALER_MINTDB_RefreshSession *refresh_session) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&refresh_session->num_oldcoins), - GNUNET_PQ_query_param_uint16 (&refresh_session->num_newcoins), - GNUNET_PQ_query_param_uint16 (&refresh_session->noreveal_index), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_session", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Insert a coin we know of into the DB. The coin can then be referenced by - * tables for deposits, lock and refresh functionality. - * - * @param cls plugin closure - * @param session the shared database session - * @param coin_info the public coin info - * @return #GNUNET_SYSERR upon error; #GNUNET_OK upon success - */ -static int -insert_known_coin (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinPublicInfo *coin_info) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub), - GNUNET_PQ_query_param_rsa_public_key (coin_info->denom_pub.rsa_public_key), - GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature), - GNUNET_PQ_query_param_end - }; - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_known_coin", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Retrieve the record for a known coin. - * - * @param cls the plugin closure - * @param session the database session handle - * @param coin_pub the public key of the coin to search for - * @param coin_info place holder for the returned coin information object - * @return #GNUNET_SYSERR upon error; #GNUNET_NO if no coin is found; #GNUNET_OK - * if upon succesfullying retrieving the record data info @a - * coin_info - */ -static int -get_known_coin (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_CoinPublicInfo *coin_info) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_end - }; - int nrows; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_known_coin", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - PQclear (result); - return GNUNET_NO; - } - GNUNET_assert (1 == nrows); /* due to primary key */ - if (NULL == coin_info) - return GNUNET_YES; - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &coin_info->denom_pub.rsa_public_key), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &coin_info->denom_sig.rsa_signature), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - PQclear (result); - coin_info->coin_pub = *coin_pub; - return GNUNET_OK; -} - - -/** - * Store the given /refresh/melt request in the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param oldcoin_index index of the coin to store - * @param melt melt operation details to store; includes - * the session hash of the melt - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -static int -postgres_insert_refresh_melt (void *cls, - struct TALER_MINTDB_Session *session, - uint16_t oldcoin_index, - const struct TALER_MINTDB_RefreshMelt *melt) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&melt->coin.coin_pub), - GNUNET_PQ_query_param_auto_from_type (&melt->session_hash), - GNUNET_PQ_query_param_uint16 (&oldcoin_index), - GNUNET_PQ_query_param_auto_from_type (&melt->coin_sig), - TALER_PQ_query_param_amount (&melt->amount_with_fee), - TALER_PQ_query_param_amount (&melt->melt_fee), - GNUNET_PQ_query_param_end - }; - int ret; - - /* check if the coin is already known */ - ret = get_known_coin (cls, - session, - &melt->coin.coin_pub, - NULL); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_NO == ret) /* if not, insert it */ - { - ret = insert_known_coin (cls, - session, - &melt->coin); - if (ret == GNUNET_SYSERR) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - } - /* insert the melt */ - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_melt", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Get information about melted coin details from the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash session hash of the melt operation - * @param oldcoin_index index of the coin to retrieve - * @param melt melt data to fill in, can be NULL - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -static int -postgres_get_refresh_melt (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t oldcoin_index, - struct TALER_MINTDB_RefreshMelt *melt) -{ - PGresult *result; - struct TALER_CoinPublicInfo coin; - struct TALER_CoinSpendSignatureP coin_sig; - struct TALER_Amount amount_with_fee; - struct TALER_Amount melt_fee; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&oldcoin_index), - GNUNET_PQ_query_param_end - }; - int nrows; - - /* check if the melt record exists and get it */ - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_melt", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "get_refresh_melt() returned 0 matching rows\n"); - PQclear (result); - return GNUNET_NO; - } - GNUNET_assert (1 == nrows); /* due to primary key constraint */ - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin.coin_pub), - GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &coin_sig), - TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee), - TALER_PQ_result_spec_amount ("melt_fee", &melt_fee), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - } - /* fetch the coin info and denomination info */ - if (GNUNET_OK != get_known_coin (cls, - session, - &coin.coin_pub, - &coin)) - return GNUNET_SYSERR; - if (NULL == melt) - { - GNUNET_CRYPTO_rsa_signature_free (coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (coin.denom_pub.rsa_public_key); - return GNUNET_OK; - } - melt->coin = coin; - melt->coin_sig = coin_sig; - melt->session_hash = *session_hash; - melt->amount_with_fee = amount_with_fee; - melt->melt_fee = melt_fee; - return GNUNET_OK; -} - - -/** - * Store in the database which coin(s) we want to create - * in a given refresh operation. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param num_newcoins number of coins to generate, size of the @a denom_pubs array - * @param denom_pubs array denominations of the coins to create - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -static int -postgres_insert_refresh_order (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t num_newcoins, - const struct TALER_DenominationPublicKey *denom_pubs) -{ - unsigned int i; - - for (i=0;i<(unsigned int) num_newcoins;i++) - { - uint16_t newcoin_off = (uint16_t) i; - PGresult *result; - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint16 (&newcoin_off), - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_rsa_public_key (denom_pubs[i].rsa_public_key), - GNUNET_PQ_query_param_end - }; - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_order", - params); - } - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - PQclear (result); - } - return GNUNET_OK; -} - - -/** - * We allocated some @a denom_pubs information, but now need - * to abort. Free allocated memory. - * - * @param denom_pubs data to free (but not the array itself) - * @param denom_pubs_len length of @a denom_pubs array - */ -static void -free_dpk_result (struct TALER_DenominationPublicKey *denom_pubs, - unsigned int denom_pubs_len) -{ - unsigned int i; - - for (i=0;i<denom_pubs_len;i++) - { - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key); - denom_pubs[i].rsa_public_key = NULL; - } -} - - -/** - * Lookup in the database the coins that we want to - * create in the given refresh operation. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param num_newcoins size of the array of the @a denom_pubs array - * @param denom_pubs where to store the deomination keys - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -static int -postgres_get_refresh_order (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t num_newcoins, - struct TALER_DenominationPublicKey *denom_pubs) -{ - unsigned int i; - - for (i=0;i<(unsigned int) num_newcoins;i++) - { - uint16_t newcoin_off = (uint16_t) i; - PGresult *result; - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&newcoin_off), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_order", - params); - } - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - free_dpk_result (denom_pubs, i); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - /* FIXME: may want to distinguish between different error cases! */ - free_dpk_result (denom_pubs, i); - return GNUNET_SYSERR; - } - GNUNET_assert (1 == PQntuples (result)); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &denom_pubs[i].rsa_public_key), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_break (0); - free_dpk_result (denom_pubs, i); - return GNUNET_SYSERR; - } - PQclear (result); - } - } - return GNUNET_OK; -} - - -/** - * Store information about the commitment of the - * given coin for the given refresh session in the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension) - * @param num_newcoins coin index size of the @a commit_coins array - * @param commit_coins array of coin commitments to store - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on error - */ -static int -postgres_insert_refresh_commit_coins (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_newcoins, - const struct TALER_MINTDB_RefreshCommitCoin *commit_coins) -{ - char *rle; - size_t rle_size; - PGresult *result; - unsigned int i; - uint16_t coin_off; - - for (i=0;i<(unsigned int) num_newcoins;i++) - { - rle = TALER_refresh_link_encrypted_encode (commit_coins[i].refresh_link, - &rle_size); - if (NULL == rle) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - coin_off = (uint16_t) i; - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&cnc_index), - GNUNET_PQ_query_param_uint16 (&coin_off), - GNUNET_PQ_query_param_fixed_size (rle, - rle_size), - GNUNET_PQ_query_param_fixed_size (commit_coins[i].coin_ev, - commit_coins[i].coin_ev_size), - GNUNET_PQ_query_param_end - }; - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_commit_coin", - params); - } - GNUNET_free (rle); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - } - return GNUNET_OK; -} - - -/** - * We allocated some @a commit_coin information, but now need - * to abort. Free allocated memory. - * - * @param commit_coins data to free (but not the array itself) - * @param commit_coins_len length of @a commit_coins array - */ -static void -free_cc_result (struct TALER_MINTDB_RefreshCommitCoin *commit_coins, - unsigned int commit_coins_len) -{ - unsigned int i; - - for (i=0;i<commit_coins_len;i++) - { - GNUNET_free (commit_coins[i].refresh_link); - commit_coins[i].refresh_link = NULL; - GNUNET_free (commit_coins[i].coin_ev); - commit_coins[i].coin_ev = NULL; - commit_coins[i].coin_ev_size = 0; - } -} - - -/** - * Obtain information about the commitment of the - * given coin of the given refresh session from the database. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index set index (1st dimension) - * @param num_newcoins size of the @a commit_coins array - * @param[out] commit_coins array of coin commitments to return - * @return #GNUNET_OK on success - * #GNUNET_NO if not found - * #GNUNET_SYSERR on error - */ -static int -postgres_get_refresh_commit_coins (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_newcoins, - struct TALER_MINTDB_RefreshCommitCoin *commit_coins) -{ - unsigned int i; - - for (i=0;i<(unsigned int) num_newcoins;i++) - { - uint16_t newcoin_off = (uint16_t) i; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&cnc_index), - GNUNET_PQ_query_param_uint16 (&newcoin_off), - GNUNET_PQ_query_param_end - }; - void *c_buf; - size_t c_buf_size; - void *rl_buf; - size_t rl_buf_size; - struct TALER_RefreshLinkEncrypted *rl; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_commit_coin", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - free_cc_result (commit_coins, i); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - free_cc_result (commit_coins, i); - return GNUNET_NO; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_variable_size ("link_vector_enc", - &rl_buf, - &rl_buf_size), - GNUNET_PQ_result_spec_variable_size ("coin_ev", - &c_buf, - &c_buf_size), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_YES != - GNUNET_PQ_extract_result (result, rs, 0)) - { - PQclear (result); - free_cc_result (commit_coins, i); - return GNUNET_SYSERR; - } - } - PQclear (result); - if (rl_buf_size < sizeof (struct TALER_CoinSpendPrivateKeyP)) - { - GNUNET_free (c_buf); - GNUNET_free (rl_buf); - free_cc_result (commit_coins, i); - return GNUNET_SYSERR; - } - rl = TALER_refresh_link_encrypted_decode (rl_buf, - rl_buf_size); - GNUNET_free (rl_buf); - commit_coins[i].refresh_link = rl; - commit_coins[i].coin_ev = c_buf; - commit_coins[i].coin_ev_size = c_buf_size; - } - return GNUNET_YES; -} - - -/** - * Store the commitment to the given (encrypted) refresh link data - * for the given refresh session. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension) - * @param num_links size of the @a links array to return - * @param[out] links array of link information to store return - * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success - */ -static int -postgres_insert_refresh_commit_links (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_links, - const struct TALER_RefreshCommitLinkP *links) -{ - uint16_t i; - - for (i=0;i<num_links;i++) - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_auto_from_type (&links[i].transfer_pub), - GNUNET_PQ_query_param_uint16 (&cnc_index), - GNUNET_PQ_query_param_uint16 (&i), - GNUNET_PQ_query_param_auto_from_type (&links[i].shared_secret_enc), - GNUNET_PQ_query_param_end - }; - - PGresult *result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_commit_link", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - PQclear (result); - } - return GNUNET_OK; -} - - -/** - * Obtain the commited (encrypted) refresh link data - * for the given refresh session. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @param cnc_index cut and choose index (1st dimension) - * @param num_links size of the @a commit_link array - * @param[out] links array of link information to return - * @return #GNUNET_SYSERR on internal error, - * #GNUNET_NO if commitment was not found - * #GNUNET_OK on success - */ -static int -postgres_get_refresh_commit_links (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t cnc_index, - uint16_t num_links, - struct TALER_RefreshCommitLinkP *links) -{ - uint16_t i; - - for (i=0;i<num_links;i++) - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&cnc_index), - GNUNET_PQ_query_param_uint16 (&i), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_commit_link", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", - &links[i].transfer_pub), - GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", - &links[i].shared_secret_enc), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_YES != - GNUNET_PQ_extract_result (result, rs, 0)) - { - PQclear (result); - return GNUNET_SYSERR; - } - } - PQclear (result); - } - return GNUNET_OK; -} - - -/** - * Get all of the information from the given melt commit operation. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param session database connection to use - * @param session_hash hash to identify refresh session - * @return NULL if the @a session_hash does not correspond to any known melt - * operation - */ -static struct TALER_MINTDB_MeltCommitment * -postgres_get_melt_commitment (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash) -{ - struct TALER_MINTDB_RefreshSession rs; - struct TALER_MINTDB_MeltCommitment *mc; - uint16_t cnc_index; - unsigned int i; - - if (GNUNET_OK != - postgres_get_refresh_session (cls, - session, - session_hash, - &rs)) - return NULL; - mc = GNUNET_new (struct TALER_MINTDB_MeltCommitment); - mc->num_newcoins = rs.num_newcoins; - mc->num_oldcoins = rs.num_oldcoins; - mc->melts = GNUNET_malloc (mc->num_oldcoins * - sizeof (struct TALER_MINTDB_RefreshMelt)); - for (i=0;i<mc->num_oldcoins;i++) - if (GNUNET_OK != - postgres_get_refresh_melt (cls, - session, - session_hash, - (uint16_t) i, - &mc->melts[i])) - goto cleanup; - mc->denom_pubs = GNUNET_malloc (mc->num_newcoins * - sizeof (struct TALER_DenominationPublicKey)); - if (GNUNET_OK != - postgres_get_refresh_order (cls, - session, - session_hash, - mc->num_newcoins, - mc->denom_pubs)) - goto cleanup; - for (cnc_index=0;cnc_index<TALER_CNC_KAPPA;cnc_index++) - { - mc->commit_coins[cnc_index] - = GNUNET_malloc (mc->num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - if (GNUNET_OK != - postgres_get_refresh_commit_coins (cls, - session, - session_hash, - cnc_index, - mc->num_newcoins, - mc->commit_coins[cnc_index])) - goto cleanup; - mc->commit_links[cnc_index] - = GNUNET_malloc (mc->num_oldcoins * - sizeof (struct TALER_RefreshCommitLinkP)); - if (GNUNET_OK != - postgres_get_refresh_commit_links (cls, - session, - session_hash, - cnc_index, - mc->num_oldcoins, - mc->commit_links[cnc_index])) - goto cleanup; - } - return mc; - - cleanup: - common_free_melt_commitment (cls, mc); - return NULL; -} - - -/** - * Insert signature of a new coin generated during refresh into - * the database indexed by the refresh session and the index - * of the coin. This data is later used should an old coin - * be used to try to obtain the private keys during "/refresh/link". - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash hash to identify refresh session - * @param newcoin_index coin index - * @param ev_sig coin signature - * @return #GNUNET_OK on success - */ -static int -postgres_insert_refresh_out (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - uint16_t newcoin_index, - const struct TALER_DenominationSignature *ev_sig) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_uint16 (&newcoin_index), - GNUNET_PQ_query_param_rsa_signature (ev_sig->rsa_signature), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_refresh_out", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Obtain the link data of a coin, that is the encrypted link - * information, the denomination keys and the signatures. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash refresh session to get linkage data for - * @return all known link data for the session - */ -static struct TALER_MINTDB_LinkDataList * -postgres_get_link_data_list (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash) -{ - struct TALER_MINTDB_LinkDataList *ldl; - struct TALER_MINTDB_LinkDataList *pos; - int i; - int nrows; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_link", - params); - - ldl = NULL; - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return NULL; - } - nrows = PQntuples (result); - if (0 == nrows) - { - PQclear (result); - return NULL; - } - - for (i = 0; i < nrows; i++) - { - struct TALER_RefreshLinkEncrypted *link_enc; - struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; - struct GNUNET_CRYPTO_rsa_Signature *sig; - void *ld_buf; - size_t ld_buf_size; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_variable_size ("link_vector_enc", - &ld_buf, - &ld_buf_size), - GNUNET_PQ_result_spec_rsa_signature ("ev_sig", - &sig), - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &denom_pub), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, i)) - { - PQclear (result); - GNUNET_break (0); - common_free_link_data_list (cls, - ldl); - return NULL; - } - if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) - { - PQclear (result); - GNUNET_free (ld_buf); - common_free_link_data_list (cls, - ldl); - return NULL; - } - link_enc = TALER_refresh_link_encrypted_decode (ld_buf, - ld_buf_size); - GNUNET_free (ld_buf); - pos = GNUNET_new (struct TALER_MINTDB_LinkDataList); - pos->next = ldl; - pos->link_data_enc = link_enc; - pos->denom_pub.rsa_public_key = denom_pub; - pos->ev_sig.rsa_signature = sig; - ldl = pos; - } - return ldl; -} - - -/** - * Obtain shared secret and transfer public key from the public key of - * the coin. This information and the link information returned by - * #postgres_get_link_data_list() enable the owner of an old coin to - * determine the private keys of the new coins after the melt. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param coin_pub public key of the coin - * @param tdc function to call for each session the coin was melted into - * @param tdc_cls closure for @a tdc - * @return #GNUNET_OK on success, - * #GNUNET_NO on failure (not found) - * #GNUNET_SYSERR on internal failure (database issue) - */ -static int -postgres_get_transfer (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_MINTDB_TransferDataCallback tdc, - void *tdc_cls) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_end - }; - PGresult *result; - int nrows; - int i; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_transfer", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - /* no matches found */ - PQclear (result); - return GNUNET_NO; - } - for (i=0;i<nrows;i++) - { - struct GNUNET_HashCode session_hash; - struct TALER_TransferPublicKeyP transfer_pub; - struct TALER_EncryptedLinkSecretP shared_secret_enc; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", &transfer_pub), - GNUNET_PQ_result_spec_auto_from_type ("link_secret_enc", &shared_secret_enc), - GNUNET_PQ_result_spec_auto_from_type ("session_hash", &session_hash), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_break (0); - return GNUNET_SYSERR; - } - tdc (tdc_cls, - &session_hash, - &transfer_pub, - &shared_secret_enc); - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Compile a list of all (historic) transactions performed - * with the given coin (/refresh/melt and /deposit operations). - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param coin_pub coin to investigate - * @return list of transactions, NULL if coin is fresh - */ -static struct TALER_MINTDB_TransactionList * -postgres_get_coin_transactions (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub) -{ - struct TALER_MINTDB_TransactionList *head; - - head = NULL; - /* check deposits */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub), - GNUNET_PQ_query_param_end - }; - int nrows; - int i; - PGresult *result; - struct TALER_MINTDB_TransactionList *tl; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_deposit_with_coin_pub", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - PQclear (result); - goto cleanup; - } - nrows = PQntuples (result); - for (i = 0; i < nrows; i++) - { - struct TALER_MINTDB_Deposit *deposit; - - deposit = GNUNET_new (struct TALER_MINTDB_Deposit); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", - &deposit->coin.denom_pub.rsa_public_key), - GNUNET_PQ_result_spec_rsa_signature ("denom_sig", - &deposit->coin.denom_sig.rsa_signature), - GNUNET_PQ_result_spec_uint64 ("transaction_id", - &deposit->transaction_id), - TALER_PQ_result_spec_amount ("amount_with_fee", - &deposit->amount_with_fee), - TALER_PQ_result_spec_amount ("deposit_fee", - &deposit->deposit_fee), - GNUNET_PQ_result_spec_absolute_time ("timestamp", - &deposit->timestamp), - GNUNET_PQ_result_spec_absolute_time ("refund_deadline", - &deposit->refund_deadline), - GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", - &deposit->merchant_pub), - GNUNET_PQ_result_spec_auto_from_type ("h_contract", - &deposit->h_contract), - GNUNET_PQ_result_spec_auto_from_type ("h_wire", - &deposit->h_wire), - TALER_PQ_result_spec_json ("wire", - &deposit->wire), - GNUNET_PQ_result_spec_auto_from_type ("coin_sig", - &deposit->csig), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, i)) - { - GNUNET_break (0); - GNUNET_free (deposit); - PQclear (result); - goto cleanup; - } - deposit->coin.coin_pub = *coin_pub; - } - tl = GNUNET_new (struct TALER_MINTDB_TransactionList); - tl->next = head; - tl->type = TALER_MINTDB_TT_DEPOSIT; - tl->details.deposit = deposit; - head = tl; - continue; - } - PQclear (result); - } - /* Handle refreshing */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&coin_pub->eddsa_pub), - GNUNET_PQ_query_param_end - }; - int nrows; - int i; - PGresult *result; - struct TALER_MINTDB_TransactionList *tl; - - /* check if the melt record exists and get it */ - result = GNUNET_PQ_exec_prepared (session->conn, - "get_refresh_melt_by_coin", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - goto cleanup; - } - nrows = PQntuples (result); - for (i=0;i<nrows;i++) - { - struct TALER_MINTDB_RefreshMelt *melt; - - melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("session_hash", - &melt->session_hash), - /* oldcoin_index not needed */ - GNUNET_PQ_result_spec_auto_from_type ("coin_sig", - &melt->coin_sig), - TALER_PQ_result_spec_amount ("amount_with_fee", - &melt->amount_with_fee), - TALER_PQ_result_spec_amount ("melt_fee", - &melt->melt_fee), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - GNUNET_free (melt); - PQclear (result); - goto cleanup; - } - melt->coin.coin_pub = *coin_pub; - } - tl = GNUNET_new (struct TALER_MINTDB_TransactionList); - tl->next = head; - tl->type = TALER_MINTDB_TT_REFRESH_MELT; - tl->details.melt = melt; - head = tl; - continue; - } - PQclear (result); - } - return head; - cleanup: - if (NULL != head) - common_free_coin_transaction_list (cls, - head); - return NULL; -} - - -/** - * Lookup the list of Taler transactions that were aggregated - * into a wire transfer by the respective @a wtid. - * - * @param cls closure - * @param session database connection - * @param wtid the raw wire transfer identifier we used - * @param cb function to call on each transaction found - * @param cb_cls closure for @a cb - * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors, - * #GNUNET_NO if we found no results - */ -static int -postgres_lookup_wire_transfer (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_WireTransferIdentifierRawP *wtid, - TALER_MINTDB_WireTransferDataCallback cb, - void *cb_cls) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (wtid), - GNUNET_PQ_query_param_end - }; - int nrows; - int i; - - /* check if the melt record exists and get it */ - result = GNUNET_PQ_exec_prepared (session->conn, - "lookup_transactions", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "lookup_wire_transfer() returned 0 matching rows\n"); - PQclear (result); - return GNUNET_NO; - } - for (i=0;i<nrows;i++) - { - struct GNUNET_HashCode h_contract; - struct GNUNET_HashCode h_wire; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_MerchantPublicKeyP merchant_pub; - uint64_t transaction_id; - struct GNUNET_TIME_Absolute exec_time; - struct TALER_Amount coin_amount; - struct TALER_Amount coin_fee; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("h_contract", &h_contract), - GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire), - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub), - GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub), - GNUNET_PQ_result_spec_uint64 ("transaction_id", &transaction_id), - GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time), - TALER_PQ_result_spec_amount ("coin_amount", &coin_amount), - TALER_PQ_result_spec_amount ("coin_fee", &coin_fee), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, i)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - cb (cb_cls, - &merchant_pub, - &h_wire, - &h_contract, - transaction_id, - &coin_pub, - &coin_amount, - &coin_fee); - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Try to find the wire transfer details for a deposit operation. - * If we did not execute the deposit yet, return when it is supposed - * to be executed. - * - * @param cls closure - * @param session database connection - * @param h_contract hash of the contract - * @param h_wire hash of merchant wire details - * @param coin_pub public key of deposited coin - * @param merchant_pub merchant public key - * @param transaction_id transaction identifier - * @param cb function to call with the result - * @param cb_cls closure to pass to @a cb - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors, - * #GNUNET_NO if nothing was found - */ -static int -postgres_wire_lookup_deposit_wtid (void *cls, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_wire, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_MerchantPublicKeyP *merchant_pub, - uint64_t transaction_id, - TALER_MINTDB_DepositWtidCallback cb, - void *cb_cls) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_auto_from_type (h_contract), - GNUNET_PQ_query_param_auto_from_type (h_wire), - GNUNET_PQ_query_param_uint64 (&transaction_id), - GNUNET_PQ_query_param_auto_from_type (merchant_pub), - GNUNET_PQ_query_param_end - }; - int nrows; - - /* check if the melt record exists and get it */ - result = GNUNET_PQ_exec_prepared (session->conn, - "lookup_deposit_wtid", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "lookup_deposit_wtid returned 0 matching rows\n"); - PQclear (result); - - /* Check if transaction exists in deposits, so that we just - do not have a WTID yet, if so, do call the CB with a NULL wtid - and return GNUNET_YES! */ - { - struct GNUNET_PQ_QueryParam params2[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_uint64 (&transaction_id), - GNUNET_PQ_query_param_auto_from_type (merchant_pub), - GNUNET_PQ_query_param_auto_from_type (h_contract), - GNUNET_PQ_query_param_auto_from_type (h_wire), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "get_deposit_for_wtid", - params2); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - } - nrows = PQntuples (result); - if (0 == nrows) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "get_deposit_for_wtid returned 0 matching rows\n"); - PQclear (result); - return GNUNET_NO; - } - - /* Ok, we're aware of the transaction, but it has not yet been - executed */ - { - struct GNUNET_TIME_Absolute exec_time; - struct TALER_Amount coin_amount; - struct TALER_Amount coin_fee; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_amount ("amount_with_fee", &coin_amount), - TALER_PQ_result_spec_amount ("deposit_fee", &coin_fee), - GNUNET_PQ_result_spec_absolute_time ("wire_deadline", &exec_time), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - cb (cb_cls, - NULL, - &coin_amount, - &coin_fee, - exec_time); - PQclear (result); - return GNUNET_YES; - } - } - if (1 != nrows) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - { - struct TALER_WireTransferIdentifierRawP wtid; - struct GNUNET_TIME_Absolute exec_time; - struct TALER_Amount coin_amount; - struct TALER_Amount coin_fee; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("wtid_raw", &wtid), - GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time), - TALER_PQ_result_spec_amount ("coin_amount", &coin_amount), - TALER_PQ_result_spec_amount ("coin_fee", &coin_fee), - GNUNET_PQ_result_spec_end - }; - if (GNUNET_OK != GNUNET_PQ_extract_result (result, rs, 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - cb (cb_cls, - &wtid, - &coin_amount, - &coin_fee, - exec_time); - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Function called to insert aggregation information into the DB. - * - * @param cls closure - * @param session database connection - * @param wtid the raw wire transfer identifier we used - * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param h_contract which contract was this payment about - * @param transaction_id merchant's transaction ID for the payment - * @param coin_pub which public key was this payment about - * @param coin_value amount contributed by this coin in total - * @param coin_fee deposit fee charged by mint for this coin - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ -static int -postgres_insert_aggregation_tracking (void *cls, - struct TALER_MINTDB_Session *session, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_value, - const struct TALER_Amount *coin_fee) -{ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (h_contract), - GNUNET_PQ_query_param_auto_from_type (h_wire), - GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_auto_from_type (merchant_pub), - GNUNET_PQ_query_param_uint64 (&transaction_id), - GNUNET_PQ_query_param_auto_from_type (wtid), - GNUNET_PQ_query_param_absolute_time (&execution_time), - TALER_PQ_query_param_amount (coin_value), - TALER_PQ_query_param_amount (coin_fee), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "insert_aggregation_tracking", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Function called to insert wire transfer commit data into the DB. - * - * @param cls closure - * @param session database connection - * @param type type of the wire transfer (i.e. "sepa") - * @param buf buffer with wire transfer preparation data - * @param buf_size number of bytes in @a buf - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ -static int -postgres_wire_prepare_data_insert (void *cls, - struct TALER_MINTDB_Session *session, - const char *type, - const char *buf, - size_t buf_size) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1), - GNUNET_PQ_query_param_fixed_size (buf, buf_size), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "wire_prepare_data_insert", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Function called to mark wire transfer commit data as finished. - * - * @param cls closure - * @param session database connection - * @param rowid which entry to mark as finished - * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors - */ -static int -postgres_wire_prepare_data_mark_finished (void *cls, - struct TALER_MINTDB_Session *session, - unsigned long long rowid) -{ - uint64_t serial_id = rowid; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_uint64 (&serial_id), - GNUNET_PQ_query_param_end - }; - PGresult *result; - - result = GNUNET_PQ_exec_prepared (session->conn, - "wire_prepare_data_mark_done", - params); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Function called to get an unfinished wire transfer - * preparation data. Fetches at most one item. - * - * @param cls closure - * @param session database connection - * @param type type fo the wire transfer (i.e. "sepa") - * @param cb function to call for ONE unfinished item - * @param cb_cls closure for @a cb - * @return #GNUNET_OK on success, - * #GNUNET_NO if there are no entries, - * #GNUNET_SYSERR on DB errors - */ -static int -postgres_wire_prepare_data_get (void *cls, - struct TALER_MINTDB_Session *session, - const char *type, - TALER_MINTDB_WirePreparationCallback cb, - void *cb_cls) -{ - PGresult *result; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_fixed_size (type, strlen (type) + 1), - GNUNET_PQ_query_param_end - }; - - result = GNUNET_PQ_exec_prepared (session->conn, - "wire_prepare_data_get", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - if (1 != PQntuples (result)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - - { - uint64_t serial_id; - void *buf = NULL; - size_t buf_size; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("serial_id", - &serial_id), - GNUNET_PQ_result_spec_variable_size ("buf", - &buf, - &buf_size), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - 0)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - cb (cb_cls, - serial_id, - buf, - buf_size); - GNUNET_PQ_cleanup_result (rs); - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Initialize Postgres database subsystem. - * - * @param cls a configuration instance - * @return NULL on error, otherwise a `struct TALER_MINTDB_Plugin` - */ -void * -libtaler_plugin_mintdb_postgres_init (void *cls) -{ - struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct PostgresClosure *pg; - struct TALER_MINTDB_Plugin *plugin; - - pg = GNUNET_new (struct PostgresClosure); - - if (0 != pthread_key_create (&pg->db_conn_threadlocal, - &db_conn_destroy)) - { - TALER_LOG_ERROR ("Cannnot create pthread key.\n"); - GNUNET_free (pg); - return NULL; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "mintdb-postgres", - "db_conn_str", - &pg->connection_cfg_str)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mintdb-postgres", - "db_conn_str"); - GNUNET_free (pg); - return NULL; - } - plugin = GNUNET_new (struct TALER_MINTDB_Plugin); - plugin->cls = pg; - plugin->get_session = &postgres_get_session; - plugin->drop_temporary = &postgres_drop_temporary; - plugin->create_tables = &postgres_create_tables; - plugin->start = &postgres_start; - plugin->commit = &postgres_commit; - plugin->rollback = &postgres_rollback; - plugin->insert_denomination_info = &postgres_insert_denomination_info; - plugin->get_denomination_info = &postgres_get_denomination_info; - plugin->reserve_get = &postgres_reserve_get; - plugin->reserves_in_insert = &postgres_reserves_in_insert; - plugin->get_withdraw_info = &postgres_get_withdraw_info; - plugin->insert_withdraw_info = &postgres_insert_withdraw_info; - plugin->get_reserve_history = &postgres_get_reserve_history; - plugin->free_reserve_history = &common_free_reserve_history; - plugin->have_deposit = &postgres_have_deposit; - plugin->mark_deposit_tiny = &postgres_mark_deposit_tiny; - plugin->mark_deposit_done = &postgres_mark_deposit_done; - plugin->get_ready_deposit = &postgres_get_ready_deposit; - plugin->iterate_matching_deposits = &postgres_iterate_matching_deposits; - plugin->insert_deposit = &postgres_insert_deposit; - plugin->get_refresh_session = &postgres_get_refresh_session; - plugin->create_refresh_session = &postgres_create_refresh_session; - plugin->insert_refresh_melt = &postgres_insert_refresh_melt; - plugin->get_refresh_melt = &postgres_get_refresh_melt; - plugin->insert_refresh_order = &postgres_insert_refresh_order; - plugin->get_refresh_order = &postgres_get_refresh_order; - plugin->insert_refresh_commit_coins = &postgres_insert_refresh_commit_coins; - plugin->get_refresh_commit_coins = &postgres_get_refresh_commit_coins; - plugin->insert_refresh_commit_links = &postgres_insert_refresh_commit_links; - plugin->get_refresh_commit_links = &postgres_get_refresh_commit_links; - plugin->get_melt_commitment = &postgres_get_melt_commitment; - plugin->free_melt_commitment = &common_free_melt_commitment; - plugin->insert_refresh_out = &postgres_insert_refresh_out; - plugin->get_link_data_list = &postgres_get_link_data_list; - plugin->free_link_data_list = &common_free_link_data_list; - plugin->get_transfer = &postgres_get_transfer; - plugin->get_coin_transactions = &postgres_get_coin_transactions; - plugin->free_coin_transaction_list = &common_free_coin_transaction_list; - plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer; - plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid; - plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking; - plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert; - plugin->wire_prepare_data_mark_finished = &postgres_wire_prepare_data_mark_finished; - plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get; - return plugin; -} - - -/** - * Shutdown Postgres database subsystem. - * - * @param cls a `struct TALER_MINTDB_Plugin` - * @return NULL (always) - */ -void * -libtaler_plugin_mintdb_postgres_done (void *cls) -{ - struct TALER_MINTDB_Plugin *plugin = cls; - struct PostgresClosure *pg = plugin->cls; - - GNUNET_free (pg->connection_cfg_str); - GNUNET_free (pg); - GNUNET_free (plugin); - return NULL; -} - -/* end of plugin_mintdb_postgres.c */ diff --git a/src/mintdb/test-mint-db-postgres.conf b/src/mintdb/test-mint-db-postgres.conf deleted file mode 100644 index 2bdb63eb0..000000000 --- a/src/mintdb/test-mint-db-postgres.conf +++ /dev/null @@ -1,8 +0,0 @@ -[mint] -#The DB plugin to use -DB = postgres - -[mintdb-postgres] - -#The connection string the plugin has to use for connecting to the database -DB_CONN_STR = postgres:///talercheck diff --git a/src/mintdb/test_mintdb.c b/src/mintdb/test_mintdb.c deleted file mode 100644 index 0938f8fab..000000000 --- a/src/mintdb/test_mintdb.c +++ /dev/null @@ -1,907 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mintdb/test_mintdb.c - * @brief test cases for DB interaction functions - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ -#include "platform.h" -#include "taler_mintdb_lib.h" -#include "taler_mintdb_plugin.h" - -static int result; - -#define FAILIF(cond) \ - do { \ - if (!(cond)){ break;} \ - GNUNET_break (0); \ - goto drop; \ - } while (0) - - -#define RND_BLK(ptr) \ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) - -#define ZR_BLK(ptr) \ - memset (ptr, 0, sizeof (*ptr)) - - -#define CURRENCY "EUR" - -static struct TALER_MINTDB_Plugin *plugin; - -/** - * Checks if the given reserve has the given amount of balance and expiry - * - * @param session the database connection - * @param pub the public key of the reserve - * @param value balance value - * @param fraction balance fraction - * @param currency currency of the reserve - * @return #GNUNET_OK if the given reserve has the same balance and expiration - * as the given parameters; #GNUNET_SYSERR if not - */ -static int -check_reserve (struct TALER_MINTDB_Session *session, - const struct TALER_ReservePublicKeyP *pub, - uint64_t value, - uint32_t fraction, - const char *currency) -{ - struct TALER_MINTDB_Reserve reserve; - - reserve.pub = *pub; - - FAILIF (GNUNET_OK != - plugin->reserve_get (plugin->cls, - session, - &reserve)); - FAILIF (value != reserve.balance.value); - FAILIF (fraction != reserve.balance.fraction); - FAILIF (0 != strcmp (currency, reserve.balance.currency)); - - return GNUNET_OK; - drop: - return GNUNET_SYSERR; -} - - -struct DenomKeyPair -{ - struct TALER_DenominationPrivateKey priv; - struct TALER_DenominationPublicKey pub; -}; - - -/** - * Destroy a denomination key pair. The key is not necessarily removed from the DB. - * - * @param dkp the keypair to destroy - */ -static void -destroy_denom_key_pair (struct DenomKeyPair *dkp) -{ - GNUNET_CRYPTO_rsa_public_key_free (dkp->pub.rsa_public_key); - GNUNET_CRYPTO_rsa_private_key_free (dkp->priv.rsa_private_key); - GNUNET_free (dkp); -} - - -/** - * Create a denominaiton key pair by registering the denomination in the DB. - * - * @param size the size of the denomination key - * @param session the DB session - * @return the denominaiton key pair; NULL upon error - */ -static struct DenomKeyPair * -create_denom_key_pair (unsigned int size, - struct TALER_MINTDB_Session *session, - const struct TALER_Amount *value, - const struct TALER_Amount *fee_withdraw, - const struct TALER_Amount *fee_deposit, - const struct TALER_Amount *fee_refresh) -{ - struct DenomKeyPair *dkp; - struct TALER_MINTDB_DenominationKeyIssueInformation dki; - - dkp = GNUNET_new (struct DenomKeyPair); - dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size); - GNUNET_assert (NULL != dkp->priv.rsa_private_key); - dkp->pub.rsa_public_key - = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv.rsa_private_key); - - /* Using memset() as fields like master key and signature - are not properly initialized for this test. */ - memset (&dki, - 0, - sizeof (struct TALER_MINTDB_DenominationKeyIssueInformation)); - dki.denom_pub = dkp->pub; - dki.issue.properties.start = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton - (GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - GNUNET_TIME_UNIT_HOURS)); - dki.issue.properties.expire_spend = GNUNET_TIME_absolute_hton - (GNUNET_TIME_absolute_add - (GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 2))); - dki.issue.properties.expire_legal = GNUNET_TIME_absolute_hton - (GNUNET_TIME_absolute_add - (GNUNET_TIME_absolute_get (), - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 3))); - TALER_amount_hton (&dki.issue.properties.value, value); - TALER_amount_hton (&dki.issue.properties.fee_withdraw, fee_withdraw); - TALER_amount_hton (&dki.issue.properties.fee_deposit, fee_deposit); - TALER_amount_hton (&dki.issue.properties.fee_refresh, fee_refresh); - GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key, - &dki.issue.properties.denom_hash); - if (GNUNET_OK != - plugin->insert_denomination_info (plugin->cls, - session, - &dki.denom_pub, - &dki.issue)) - { - GNUNET_break(0); - destroy_denom_key_pair (dkp); - return NULL; - } - return dkp; -} - -static struct TALER_Amount value; -static struct TALER_Amount fee_withdraw; -static struct TALER_Amount fee_deposit; -static struct TALER_Amount fee_refresh; -static struct TALER_Amount amount_with_fee; - -static void -free_refresh_commit_coins_array(struct TALER_MINTDB_RefreshCommitCoin - *commit_coins, - unsigned int size) -{ - unsigned int cnt; - struct TALER_MINTDB_RefreshCommitCoin *ccoin; - struct TALER_RefreshLinkEncrypted *rlink; - - for (cnt = 0; cnt < size; cnt++) - { - ccoin = &commit_coins[cnt]; - GNUNET_free_non_null (ccoin->coin_ev); - rlink = (struct TALER_RefreshLinkEncrypted *) ccoin->refresh_link; - GNUNET_free_non_null (rlink); - } - GNUNET_free (commit_coins); -} - -#define MELT_NEW_COINS 5 - -static int -test_refresh_commit_coins (struct TALER_MINTDB_Session *session, - struct TALER_MINTDB_RefreshSession *refresh_session, - const struct GNUNET_HashCode *session_hash) -{ - struct TALER_MINTDB_RefreshCommitCoin *commit_coins; - struct TALER_MINTDB_RefreshCommitCoin *ret_commit_coins; - struct TALER_MINTDB_RefreshCommitCoin *a_ccoin; - struct TALER_RefreshLinkEncrypted *a_rlink; - struct TALER_MINTDB_RefreshCommitCoin *b_ccoin; - struct TALER_RefreshLinkEncrypted *b_rlink; - size_t size; - unsigned int cnt; - uint16_t cnc_index; - int ret; - - #define COIN_ENC_MAX_SIZE 512 - ret = GNUNET_SYSERR; - ret_commit_coins = NULL; - commit_coins = GNUNET_new_array (MELT_NEW_COINS, - struct TALER_MINTDB_RefreshCommitCoin); - cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32 - (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX)); - for (cnt=0; cnt < MELT_NEW_COINS; cnt++) - { - struct TALER_MINTDB_RefreshCommitCoin *ccoin; - struct TALER_RefreshLinkEncrypted *rlink; - ccoin = &commit_coins[cnt]; - size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - COIN_ENC_MAX_SIZE); - rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size); - ccoin->refresh_link = rlink; - ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64 - (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE); - ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size); - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - ccoin->coin_ev, - ccoin->coin_ev_size); - rlink->blinding_key_enc_size = size; - RND_BLK (&rlink->coin_priv_enc); - rlink->blinding_key_enc = (const char *) &rlink[1]; - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - (void *)rlink->blinding_key_enc, - rlink->blinding_key_enc_size); - } - FAILIF (GNUNET_OK != - plugin->insert_refresh_commit_coins (plugin->cls, - session, - session_hash, - cnc_index, - MELT_NEW_COINS, - commit_coins)); - ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS, - struct TALER_MINTDB_RefreshCommitCoin); - FAILIF (GNUNET_OK != - plugin->get_refresh_commit_coins (plugin->cls, - session, - session_hash, - cnc_index, - MELT_NEW_COINS, - ret_commit_coins)); - /* compare the refresh commit coin arrays */ - for (cnt = 0; cnt < MELT_NEW_COINS; cnt++) - { - a_ccoin = &commit_coins[cnt]; - b_ccoin = &ret_commit_coins[cnt]; - FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size); - FAILIF (0 != memcmp (a_ccoin->coin_ev, - a_ccoin->coin_ev, - a_ccoin->coin_ev_size)); - a_rlink = a_ccoin->refresh_link; - b_rlink = b_ccoin->refresh_link; - FAILIF (a_rlink->blinding_key_enc_size != b_rlink->blinding_key_enc_size); - FAILIF (0 != memcmp (a_rlink->blinding_key_enc, - b_rlink->blinding_key_enc, - a_rlink->blinding_key_enc_size)); - FAILIF (0 != memcmp (a_rlink->coin_priv_enc, - b_rlink->coin_priv_enc, - sizeof (a_rlink->coin_priv_enc))); - } - ret = GNUNET_OK; - - drop: - if (NULL != ret_commit_coins) - free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS); - if (NULL != commit_coins) - free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS); - return ret; -} - -/** - * Function to test melting of coins as part of a refresh session - * - * @param session the database session - * @param refresh_session the refresh session - * @return #GNUNET_OK if everything went well; #GNUNET_SYSERR if not - */ -static int -test_melting (struct TALER_MINTDB_Session *session) -{ -#define MELT_OLD_COINS 10 - struct TALER_MINTDB_RefreshSession refresh_session; - struct TALER_MINTDB_RefreshSession ret_refresh_session; - struct GNUNET_HashCode session_hash; - struct DenomKeyPair *dkp; - struct DenomKeyPair **new_dkp; - /* struct TALER_CoinPublicInfo *coins; */ - struct TALER_MINTDB_RefreshMelt *melts; - struct TALER_DenominationPublicKey *new_denom_pubs; - struct TALER_DenominationPublicKey *ret_denom_pubs; - unsigned int cnt; - int ret; - - ret = GNUNET_SYSERR; - RND_BLK (&refresh_session); - RND_BLK (&session_hash); - melts = NULL; - dkp = NULL; - new_dkp = NULL; - new_denom_pubs = NULL; - ret_denom_pubs = NULL; - /* create and test a refresh session */ - refresh_session.num_oldcoins = MELT_OLD_COINS; - refresh_session.num_newcoins = 1; - refresh_session.noreveal_index = 1; - FAILIF (GNUNET_OK != plugin->create_refresh_session (plugin->cls, - session, - &session_hash, - &refresh_session)); - FAILIF (GNUNET_OK != plugin->get_refresh_session (plugin->cls, - session, - &session_hash, - &ret_refresh_session)); - FAILIF (0 != memcmp (&ret_refresh_session, - &refresh_session, - sizeof (refresh_session))); - - /* create a denomination (value: 1; fraction: 100) */ - dkp = create_denom_key_pair (512, session, - &value, - &fee_withdraw, - &fee_deposit, - &fee_refresh); - /* create MELT_OLD_COINS number of refresh melts */ - melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_MINTDB_RefreshMelt); - for (cnt=0; cnt < MELT_OLD_COINS; cnt++) - { - RND_BLK (&melts[cnt].coin.coin_pub); - melts[cnt].coin.denom_sig.rsa_signature = - GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key, - &melts[cnt].coin.coin_pub, - sizeof (melts[cnt].coin.coin_pub)); - melts[cnt].coin.denom_pub = dkp->pub; - RND_BLK (&melts[cnt].coin_sig); - melts[cnt].session_hash = session_hash; - melts[cnt].amount_with_fee = amount_with_fee; - melts[cnt].melt_fee = fee_refresh; - FAILIF (GNUNET_OK != plugin->insert_refresh_melt (plugin->cls, - session, - cnt, - &melts[cnt])); - } - for (cnt = 0; cnt < MELT_OLD_COINS; cnt++) - { - struct TALER_MINTDB_RefreshMelt ret_melt; - FAILIF (GNUNET_OK != plugin->get_refresh_melt (plugin->cls, - session, - &session_hash, - cnt, - &ret_melt)); - FAILIF (0 != GNUNET_CRYPTO_rsa_signature_cmp - (ret_melt.coin.denom_sig.rsa_signature, - melts[cnt].coin.denom_sig.rsa_signature)); - FAILIF (0 != memcmp (&ret_melt.coin.coin_pub, - &melts[cnt].coin.coin_pub, - sizeof (ret_melt.coin.coin_pub))); - FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp - (ret_melt.coin.denom_pub.rsa_public_key, - melts[cnt].coin.denom_pub.rsa_public_key)); - FAILIF (0 != memcmp (&ret_melt.coin_sig, - &melts[cnt].coin_sig, - sizeof (ret_melt.coin_sig))); - FAILIF (0 != memcmp (&ret_melt.session_hash, - &melts[cnt].session_hash, - sizeof (ret_melt.session_hash))); - FAILIF (0 != TALER_amount_cmp (&ret_melt.amount_with_fee, - &melts[cnt].amount_with_fee)); - FAILIF (0 != TALER_amount_cmp (&ret_melt.melt_fee, - &melts[cnt].melt_fee)); - GNUNET_CRYPTO_rsa_signature_free (ret_melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (ret_melt.coin.denom_pub.rsa_public_key); - } - new_dkp = GNUNET_new_array (MELT_NEW_COINS, struct DenomKeyPair *); - new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, - struct TALER_DenominationPublicKey); - for (cnt=0; cnt < MELT_NEW_COINS; cnt++) - { - new_dkp[cnt] = create_denom_key_pair (128, session, - &value, - &fee_withdraw, - &fee_deposit, - &fee_refresh); - new_denom_pubs[cnt]=new_dkp[cnt]->pub; - } - FAILIF (GNUNET_OK != plugin->insert_refresh_order (plugin->cls, - session, - &session_hash, - MELT_NEW_COINS, - new_denom_pubs)); - ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, - struct TALER_DenominationPublicKey); - FAILIF (GNUNET_OK != plugin->get_refresh_order (plugin->cls, - session, - &session_hash, - MELT_NEW_COINS, - ret_denom_pubs)); - for (cnt=0; cnt < MELT_NEW_COINS; cnt++) - { - FAILIF (0 != GNUNET_CRYPTO_rsa_public_key_cmp - (ret_denom_pubs[cnt].rsa_public_key, - new_denom_pubs[cnt].rsa_public_key)); - } - FAILIF (GNUNET_OK != - test_refresh_commit_coins (session, - &refresh_session, - &session_hash)); - - ret = GNUNET_OK; - - drop: - if (NULL != dkp) - destroy_denom_key_pair (dkp); - if (NULL != melts) - { - for (cnt = 0; cnt < MELT_OLD_COINS; cnt++) - GNUNET_CRYPTO_rsa_signature_free (melts[cnt].coin.denom_sig.rsa_signature); - GNUNET_free (melts); - } - for (cnt = 0; - (NULL != ret_denom_pubs) && (cnt < MELT_NEW_COINS) - && (NULL != ret_denom_pubs[cnt].rsa_public_key); - cnt++) - GNUNET_CRYPTO_rsa_public_key_free (ret_denom_pubs[cnt].rsa_public_key); - GNUNET_free_non_null (ret_denom_pubs); - GNUNET_free_non_null (new_denom_pubs); - for (cnt = 0; - (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); - cnt++) - destroy_denom_key_pair (new_dkp[cnt]); - GNUNET_free_non_null (new_dkp); - return ret; -} - - -/** - * Callback that should never be called. - */ -static void -cb_wt_never (void *cls, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_value, - const struct TALER_Amount *coin_fee) -{ - GNUNET_assert (0); /* this statement should be unreachable */ -} - - -/** - * Callback that should never be called. - */ -static void -cb_wtid_never (void *cls, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_Amount *coin_contribution, - const struct TALER_Amount *coin_fee, - struct GNUNET_TIME_Absolute execution_time) -{ - GNUNET_assert (0); -} - - -static struct TALER_MerchantPublicKeyP merchant_pub_wt; -static struct GNUNET_HashCode h_wire_wt; -static struct GNUNET_HashCode h_contract_wt; -static uint64_t transaction_id_wt; -static struct TALER_CoinSpendPublicKeyP coin_pub_wt; -static struct TALER_Amount coin_value_wt; -static struct TALER_Amount coin_fee_wt; -static struct TALER_Amount transfer_value_wt; -static struct GNUNET_TIME_Absolute execution_time_wt; -static struct TALER_WireTransferIdentifierRawP wtid_wt; - - -/** - * Callback that should be called with the WT data. - */ -static void -cb_wt_check (void *cls, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *coin_value, - const struct TALER_Amount *coin_fee) -{ - GNUNET_assert (cls == &cb_wt_never); - GNUNET_assert (0 == memcmp (merchant_pub, - &merchant_pub_wt, - sizeof (struct TALER_MerchantPublicKeyP))); - GNUNET_assert (0 == memcmp (h_wire, - &h_wire_wt, - sizeof (struct GNUNET_HashCode))); - GNUNET_assert (0 == memcmp (h_contract, - &h_contract_wt, - sizeof (struct GNUNET_HashCode))); - GNUNET_assert (transaction_id == transaction_id_wt); - GNUNET_assert (0 == memcmp (coin_pub, - &coin_pub_wt, - sizeof (struct TALER_CoinSpendPublicKeyP))); - GNUNET_assert (0 == TALER_amount_cmp (coin_value, - &coin_value_wt)); - GNUNET_assert (0 == TALER_amount_cmp (coin_fee, - &coin_fee_wt)); -} - - -/** - * Callback that should be called with the WT data. - */ -static void -cb_wtid_check (void *cls, - const struct TALER_WireTransferIdentifierRawP *wtid, - const struct TALER_Amount *coin_contribution, - const struct TALER_Amount *coin_fee, - struct GNUNET_TIME_Absolute execution_time) -{ - GNUNET_assert (cls == &cb_wtid_never); - GNUNET_assert (0 == memcmp (wtid, - &wtid_wt, - sizeof (struct TALER_WireTransferIdentifierRawP))); - GNUNET_assert (execution_time.abs_value_us == - execution_time_wt.abs_value_us); - GNUNET_assert (0 == TALER_amount_cmp (coin_contribution, - &coin_value_wt)); - GNUNET_assert (0 == TALER_amount_cmp (coin_fee, - &coin_fee_wt)); -} - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration - */ -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct TALER_MINTDB_Session *session; - struct TALER_ReservePublicKeyP reserve_pub; - struct DenomKeyPair *dkp; - struct TALER_MINTDB_CollectableBlindcoin cbc; - struct TALER_MINTDB_CollectableBlindcoin cbc2; - struct TALER_MINTDB_ReserveHistory *rh; - struct TALER_MINTDB_ReserveHistory *rh_head; - struct TALER_MINTDB_BankTransfer *bt; - struct TALER_MINTDB_CollectableBlindcoin *withdraw; - struct TALER_MINTDB_Deposit deposit; - struct TALER_MINTDB_Deposit deposit2; - struct TALER_WireTransferIdentifierRawP wtid; - json_t *wire; - json_t *just; - const char * const json_wire_str = - "{ \"type\":\"SEPA\", \ -\"IBAN\":\"DE67830654080004822650\", \ -\"name\":\"GNUnet e.V.\", \ -\"bic\":\"GENODEF1SLR\", \ -\"edate\":\"1449930207000\", \ -\"r\":123456789, \ -\"address\": \"foobar\"}"; - unsigned int cnt; - - dkp = NULL; - rh = NULL; - wire = NULL; - session = NULL; - ZR_BLK (&cbc); - ZR_BLK (&cbc2); - if (NULL == - (plugin = TALER_MINTDB_plugin_load (cfg))) - { - result = 1; - return; - } - if (GNUNET_OK != - plugin->create_tables (plugin->cls, - GNUNET_YES)) - { - result = 2; - goto drop; - } - if (NULL == - (session = plugin->get_session (plugin->cls, - GNUNET_YES))) - { - result = 3; - goto drop; - } - RND_BLK (&reserve_pub); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.000010", - &value)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.000010", - &fee_withdraw)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.000010", - &fee_deposit)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":0.000010", - &fee_refresh)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.000010", - &amount_with_fee)); - - result = 4; - just = json_loads ("{ \"justification\":\"1\" }", 0, NULL); - FAILIF (GNUNET_OK != - plugin->reserves_in_insert (plugin->cls, - session, - &reserve_pub, - &value, - GNUNET_TIME_absolute_get (), - just)); - json_decref (just); - FAILIF (GNUNET_OK != - check_reserve (session, - &reserve_pub, - value.value, - value.fraction, - value.currency)); - just = json_loads ("{ \"justification\":\"2\" }", 0, NULL); - FAILIF (GNUNET_OK != - plugin->reserves_in_insert (plugin->cls, - session, - &reserve_pub, - &value, - GNUNET_TIME_absolute_get (), - just)); - json_decref (just); - FAILIF (GNUNET_OK != - check_reserve (session, - &reserve_pub, - value.value * 2, - value.fraction * 2, - value.currency)); - dkp = create_denom_key_pair (1024, session, - &value, - &fee_withdraw, - &fee_deposit, - &fee_refresh); - RND_BLK(&cbc.h_coin_envelope); - RND_BLK(&cbc.reserve_sig); - cbc.denom_pub = dkp->pub; - cbc.sig.rsa_signature - = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key, - &cbc.h_coin_envelope, - sizeof (cbc.h_coin_envelope)); - cbc.reserve_pub = reserve_pub; - cbc.amount_with_fee = value; - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee)); - FAILIF (GNUNET_OK != - plugin->insert_withdraw_info (plugin->cls, - session, - &cbc)); - FAILIF (GNUNET_OK != - check_reserve (session, - &reserve_pub, - value.value, - value.fraction, - value.currency)); - FAILIF (GNUNET_YES != - plugin->get_withdraw_info (plugin->cls, - session, - &cbc.h_coin_envelope, - &cbc2)); - FAILIF (NULL == cbc2.denom_pub.rsa_public_key); - FAILIF (0 != memcmp (&cbc2.reserve_sig, - &cbc.reserve_sig, - sizeof (cbc2.reserve_sig))); - FAILIF (0 != memcmp (&cbc2.reserve_pub, - &cbc.reserve_pub, - sizeof (cbc2.reserve_pub))); - FAILIF (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope, - cbc2.sig.rsa_signature, - dkp->pub.rsa_public_key)); - rh = plugin->get_reserve_history (plugin->cls, - session, - &reserve_pub); - FAILIF (NULL == rh); - rh_head = rh; - for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++) - { - switch (rh_head->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - bt = rh_head->details.bank; - FAILIF (0 != memcmp (&bt->reserve_pub, - &reserve_pub, - sizeof (reserve_pub))); - /* this is the amount we trasferred twice*/ - FAILIF (1 != bt->amount.value); - FAILIF (10 != bt->amount.fraction); - FAILIF (0 != strcmp (CURRENCY, bt->amount.currency)); - FAILIF (NULL == bt->wire); - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - withdraw = rh_head->details.withdraw; - FAILIF (0 != memcmp (&withdraw->reserve_pub, - &reserve_pub, - sizeof (reserve_pub))); - FAILIF (0 != memcmp (&withdraw->h_coin_envelope, - &cbc.h_coin_envelope, - sizeof (cbc.h_coin_envelope))); - break; - } - } - FAILIF (3 != cnt); - /* Tests for deposits */ - memset (&deposit, 0, sizeof (deposit)); - RND_BLK (&deposit.coin.coin_pub); - deposit.coin.denom_pub = dkp->pub; - deposit.coin.denom_sig = cbc.sig; - RND_BLK (&deposit.csig); - RND_BLK (&deposit.merchant_pub); - RND_BLK (&deposit.h_contract); - RND_BLK (&deposit.h_wire); - wire = json_loads (json_wire_str, 0, NULL); - deposit.wire = wire; - deposit.transaction_id = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); - deposit.amount_with_fee = value; - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (CURRENCY, &deposit.deposit_fee)); - FAILIF (GNUNET_OK != - plugin->insert_deposit (plugin->cls, - session, &deposit)); - FAILIF (GNUNET_YES != - plugin->have_deposit (plugin->cls, - session, - &deposit)); - deposit2 = deposit; - deposit2.transaction_id++; /* should fail if transaction id is different */ - FAILIF (GNUNET_NO != - plugin->have_deposit (plugin->cls, - session, - &deposit2)); - deposit2.transaction_id = deposit.transaction_id; - RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */ - FAILIF (GNUNET_NO != - plugin->have_deposit (plugin->cls, - session, - &deposit2)); - deposit2.merchant_pub = deposit.merchant_pub; - RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */ - FAILIF (GNUNET_NO != - plugin->have_deposit (plugin->cls, - session, - &deposit2)); - FAILIF (GNUNET_OK != test_melting (session)); - - /* setup values for wire transfer aggregation data */ - memset (&wtid, 42, sizeof (wtid)); - memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt)); - memset (&h_wire_wt, 44, sizeof (h_wire_wt)); - memset (&h_contract_wt, 45, sizeof (h_contract_wt)); - memset (&coin_pub_wt, 46, sizeof (coin_pub_wt)); - transaction_id_wt = 47; - execution_time_wt = GNUNET_TIME_absolute_get (); - memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY "KUDOS:1.000010", - &coin_value_wt)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY "KUDOS:0.000010", - &coin_fee_wt)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY "KUDOS:1.000000", - &transfer_value_wt)); - - FAILIF (GNUNET_NO != - plugin->lookup_wire_transfer (plugin->cls, - session, - &wtid_wt, - &cb_wt_never, - NULL)); - FAILIF (GNUNET_NO != - plugin->wire_lookup_deposit_wtid (plugin->cls, - session, - &h_contract_wt, - &h_wire_wt, - &coin_pub_wt, - &merchant_pub_wt, - transaction_id_wt, - &cb_wtid_never, - NULL)); - /* insert WT data */ - FAILIF (GNUNET_OK != - plugin->insert_aggregation_tracking (plugin->cls, - session, - &wtid_wt, - &merchant_pub_wt, - &h_wire_wt, - &h_contract_wt, - transaction_id_wt, - execution_time_wt, - &coin_pub_wt, - &coin_value_wt, - &coin_fee_wt)); - FAILIF (GNUNET_OK != - plugin->lookup_wire_transfer (plugin->cls, - session, - &wtid_wt, - &cb_wt_check, - &cb_wt_never)); - FAILIF (GNUNET_OK != - plugin->wire_lookup_deposit_wtid (plugin->cls, - session, - &h_contract_wt, - &h_wire_wt, - &coin_pub_wt, - &merchant_pub_wt, - transaction_id_wt, - &cb_wtid_check, - &cb_wtid_never)); - result = 0; - - drop: - if (NULL != wire) - json_decref (wire); - if (NULL != rh) - plugin->free_reserve_history (plugin->cls, - rh); - rh = NULL; - if (NULL != session) - GNUNET_break (GNUNET_OK == - plugin->drop_temporary (plugin->cls, - session)); - if (NULL != dkp) - destroy_denom_key_pair (dkp); - if (NULL != cbc.sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature); - if (NULL != cbc2.denom_pub.rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key); - if (NULL != cbc2.sig.rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature); - dkp = NULL; - TALER_MINTDB_plugin_unload (plugin); - plugin = NULL; -} - - -int -main (int argc, - char *const argv[]) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - char *argv2[] = { - "test-mint-db-<plugin_name>", /* will be replaced later */ - "-c", "test-mint-db-<plugin_name>.conf", /* will be replaced later */ - NULL, - }; - const char *plugin_name; - char *config_filename; - char *testname; - - result = -1; - if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) - { - GNUNET_break (0); - return -1; - } - plugin_name++; - (void) GNUNET_asprintf (&testname, - "test-mint-db-%s", plugin_name); - (void) GNUNET_asprintf (&config_filename, - "%s.conf", testname); - argv2[0] = argv[0]; - argv2[2] = config_filename; - if (GNUNET_OK != - GNUNET_PROGRAM_run ((sizeof (argv2)/sizeof (char *)) - 1, argv2, - testname, - "Test cases for mint database helper functions.", - options, &run, NULL)) - { - GNUNET_free (config_filename); - GNUNET_free (testname); - return 3; - } - GNUNET_free (config_filename); - GNUNET_free (testname); - return result; -} diff --git a/src/mintdb/test_mintdb_deposits.c b/src/mintdb/test_mintdb_deposits.c deleted file mode 100644 index 3ce0a35a5..000000000 --- a/src/mintdb/test_mintdb_deposits.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/test_mint_deposits.c - * @brief testcase for mint deposits - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ -#include "platform.h" -#include <libpq-fe.h> -#include <gnunet/gnunet_util_lib.h> -#include "taler_pq_lib.h" -#include "taler_mintdb_lib.h" -#include "taler_mintdb_plugin.h" - -#define MINT_CURRENCY "EUR" - -#define DB_URI "postgres:///taler" - -#define break_db_err(result) do { \ - GNUNET_break(0); \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ - } while (0) - -/** - * Shorthand for exit jumps. - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Should we not interact with a temporary table? - */ -static int persistent; - -/** - * Testcase result - */ -static int result; - -/** - * The plugin. - */ -static struct TALER_MINTDB_Plugin *plugin; - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration - */ -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - static const char wire[] = "{" - "\"type\":\"SEPA\"," - "\"IBAN\":\"DE67830654080004822650\"," - "\"NAME\":\"GNUNET E.V\"," - "\"BIC\":\"GENODEF1SRL\"" - "}"; - struct TALER_MINTDB_Deposit *deposit; - uint64_t transaction_id; - struct TALER_MINTDB_Session *session; - - deposit = NULL; - EXITIF (NULL == (plugin = TALER_MINTDB_plugin_load (cfg))); - EXITIF (GNUNET_OK != - plugin->create_tables (plugin->cls, - ! persistent)); - session = plugin->get_session (plugin->cls, - ! persistent); - EXITIF (NULL == session); - deposit = GNUNET_malloc (sizeof (struct TALER_MINTDB_Deposit) + sizeof (wire)); - /* Makeup a random coin public key */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - deposit, - sizeof (struct TALER_MINTDB_Deposit)); - /* Makeup a random 64bit transaction ID */ - transaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX); - deposit->transaction_id = GNUNET_htonll (transaction_id); - /* Random amount */ - deposit->amount_with_fee.value = - htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); - deposit->amount_with_fee.fraction = - htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)); - GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount_with_fee.currency)); - strcpy (deposit->amount_with_fee.currency, MINT_CURRENCY); - /* Copy wireformat */ - deposit->wire = json_loads (wire, 0, NULL); - EXITIF (GNUNET_OK != - plugin->insert_deposit (plugin->cls, - session, - deposit)); - EXITIF (GNUNET_OK != - plugin->have_deposit (plugin->cls, - session, - deposit)); - result = GNUNET_OK; - - EXITIF_exit: - GNUNET_free_non_null (deposit); - if (NULL != plugin) - { - TALER_MINTDB_plugin_unload (plugin); - plugin = NULL; - } -} - - -int -main (int argc, - char *const argv[]) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'T', "persist", NULL, - gettext_noop ("Use a persistent database table instead of a temporary one"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &persistent}, - GNUNET_GETOPT_OPTION_END - }; - - - persistent = GNUNET_NO; - result = GNUNET_SYSERR; - if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, argv, - "test-mint-deposits", - "testcase for mint deposits", - options, &run, NULL)) - return 3; - return (GNUNET_OK == result) ? 0 : 1; -} diff --git a/src/mintdb/test_mintdb_keyio.c b/src/mintdb/test_mintdb_keyio.c deleted file mode 100644 index aa1ba2f20..000000000 --- a/src/mintdb/test_mintdb_keyio.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e. V. (and other contributing authors) - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/test_mint_common.c - * @brief test cases for some functions in mint/mint_common.c - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ -#include "platform.h" -#include "gnunet/gnunet_util_lib.h" -#include "taler_signatures.h" -#include "taler_mintdb_lib.h" - -#define RSA_KEY_SIZE 1024 - - -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -int -main (int argc, - const char *const argv[]) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation dki; - char *enc; - size_t enc_size; - struct TALER_MINTDB_DenominationKeyIssueInformation dki_read; - char *enc_read; - size_t enc_read_size; - char *tmpfile; - int ret; - - ret = 1; - enc = NULL; - enc_read = NULL; - tmpfile = NULL; - dki.denom_priv.rsa_private_key = NULL; - dki_read.denom_priv.rsa_private_key = NULL; - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &dki.issue.signature, - sizeof (struct TALER_MasterSignatureP)); - dki.denom_priv.rsa_private_key - = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE); - enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv.rsa_private_key, - &enc); - EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_mint_common"))); - EXITIF (GNUNET_OK != TALER_MINTDB_denomination_key_write (tmpfile, &dki)); - EXITIF (GNUNET_OK != TALER_MINTDB_denomination_key_read (tmpfile, &dki_read)); - enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key, - &enc_read); - EXITIF (enc_size != enc_read_size); - EXITIF (0 != memcmp (enc, - enc_read, - enc_size)); - ret = 0; - - EXITIF_exit: - GNUNET_free_non_null (enc); - if (NULL != tmpfile) - { - (void) unlink (tmpfile); - GNUNET_free (tmpfile); - } - GNUNET_free_non_null (enc_read); - if (NULL != dki.denom_priv.rsa_private_key) - GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv.rsa_private_key); - if (NULL != dki_read.denom_priv.rsa_private_key) - GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv.rsa_private_key); - return ret; -} diff --git a/src/mintdb/test_perf_taler_mintdb.c b/src/mintdb/test_perf_taler_mintdb.c deleted file mode 100644 index 789a0dd4f..000000000 --- a/src/mintdb/test_perf_taler_mintdb.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> - */ -/** - * @file mintdb/test_perf_taler_mintdb.c - * @brief Mint database performance analysis - * @author Nicolas Fournier - */ -#include "platform.h" -#include "perf_taler_mintdb_interpreter.h" -#include "perf_taler_mintdb_init.h" - - -#define NB_DENOMINATION_INIT 2 -#define NB_DENOMINATION_SAVE 2 - -#define NB_RESERVE_INIT 4 -#define NB_RESERVE_SAVE 1 - -#define NB_DEPOSIT_INIT 1 -#define NB_DEPOSIT_SAVE 1 - -#define NB_WITHDRAW_INIT 1 -#define NB_WITHDRAW_SAVE 1 - -/** - * Allocate, copies and free all the data used in the interpreter - * Used to check for memory leaks - */ -static void -test_allocate () -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki, *dki_copy; - struct PERF_TALER_MINTDB_Reserve *reserve, *reserve_copy; - struct PERF_TALER_MINTDB_Coin *coin, *coin_copy; - struct TALER_MINTDB_Deposit *deposit, *deposit_copy; - - dki = PERF_TALER_MINTDB_denomination_init (); - reserve = PERF_TALER_MINTDB_reserve_init (); - coin = PERF_TALER_MINTDB_coin_init (dki, - reserve); - deposit = PERF_TALER_MINTDB_deposit_init (coin); - - dki_copy = PERF_TALER_MINTDB_denomination_copy (dki); - reserve_copy = PERF_TALER_MINTDB_reserve_copy (reserve); - coin_copy = PERF_TALER_MINTDB_coin_copy (coin); - deposit_copy = PERF_TALER_MINTDB_deposit_copy (deposit); - - PERF_TALER_MINTDB_denomination_free (dki); - PERF_TALER_MINTDB_denomination_free (dki_copy); - PERF_TALER_MINTDB_reserve_free (reserve); - PERF_TALER_MINTDB_reserve_free (reserve_copy); - PERF_TALER_MINTDB_coin_free (coin); - PERF_TALER_MINTDB_coin_free (coin_copy); - PERF_TALER_MINTDB_deposit_free (deposit); - PERF_TALER_MINTDB_deposit_free (deposit_copy); -} - -/** - * Runs the performances tests for the mint database - * and logs the results using Gauger - */ -int -main (int argc, char ** argv) -{ - int ret = 0; - struct PERF_TALER_MINTDB_Cmd init[] = - { - PERF_TALER_MINTDB_INIT_CMD_END ("init") - }; - struct PERF_TALER_MINTDB_Cmd benchmark[] = - { - // Denomination used to create coins - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("00 - Start of interpreter"), - - PERF_TALER_MINTDB_INIT_CMD_LOOP ("01 - denomination loop", - NB_DENOMINATION_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("01 - start transaction"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_DENOMINATION ("01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DENOMINATION ("01 - insert", - "01 - denomination"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("01 - commit transaction"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("01 - save denomination", - "01 - denomination loop", - "01 - denomination", - NB_DENOMINATION_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("01 - denomination loop end", - "01 - denomination loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("01 - init denomination complete"), - // End of initialization - // Reserve initialization - PERF_TALER_MINTDB_INIT_CMD_LOOP ("02 - init reserve loop", - NB_RESERVE_INIT), - - PERF_TALER_MINTDB_INIT_CMD_CREATE_RESERVE ("02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_RESERVE ("02 - insert", - "02 - reserve"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("02 - save reserve", - "02 - init reserve loop", - "02 - reserve", - NB_RESERVE_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("02 - init reserve end loop", - "02 - init reserve loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("02 - reserve init complete"), - // End reserve init - // Withdrawal initialization - PERF_TALER_MINTDB_INIT_CMD_LOOP ("03 - init withdraw loop", - NB_WITHDRAW_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("03 - start transaction"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - denomination load", - "03 - init withdraw loop", - "01 - save denomination"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("03 - reserve load", - "03 - init withdraw loop", - "02 - save reserve"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_WITHDRAW ("03 - withdraw", - "03 - denomination load", - "03 - reserve load"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_WITHDRAW ("03 - insert withdraw", - "03 - withdraw"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("03 - commit transaction"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("03 - coin array", - "03 - init withdraw loop", - "03 - withdraw", - NB_WITHDRAW_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("03 - withdraw init end loop", - "03 - init withdraw loop"), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("03 - withdraw init complete"), - //End of withdrawal initialization - //Deposit initialization - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("04 - time start"), - PERF_TALER_MINTDB_INIT_CMD_LOOP ("04 - deposit init loop", - NB_DEPOSIT_INIT), - PERF_TALER_MINTDB_INIT_CMD_START_TRANSACTION ("04 - start transaction"), - PERF_TALER_MINTDB_INIT_CMD_LOAD_ARRAY ("04 - coin load", - "04 - deposit init loop", - "03 - coin array"), - PERF_TALER_MINTDB_INIT_CMD_CREATE_DEPOSIT ("04 - deposit", - "04 - coin load"), - PERF_TALER_MINTDB_INIT_CMD_INSERT_DEPOSIT ("04 - insert deposit", - "04 - deposit"), - PERF_TALER_MINTDB_INIT_CMD_COMMIT_TRANSACTION ("04 - commit transaction"), - PERF_TALER_MINTDB_INIT_CMD_SAVE_ARRAY ("04 - deposit array", - "04 - deposit init loop", - "04 - deposit", - NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_END_LOOP ("04 - deposit init loop end", - "04 - deposit init loop"), - PERF_TALER_MINTDB_INIT_CMD_GET_TIME ("04 - time stop"), - PERF_TALER_MINTDB_INIT_CMD_GAUGER ("04 - gauger", - "04 - time start", - "04 - time stop", - "TEST", - "time to insert a deposit", - "deposit/sec", - NB_DEPOSIT_SAVE), - PERF_TALER_MINTDB_INIT_CMD_DEBUG ("04 - deposit init complete"), - // End of deposit initialization - PERF_TALER_MINTDB_INIT_CMD_END ("end"), - }; - - test_allocate (); - ret = PERF_TALER_MINTDB_run_benchmark ("test-perf-taler-mintdb", - "./test-mint-db-postgres.conf", - init, - benchmark); - if (GNUNET_SYSERR == ret) - return 1; - return 0; -} diff --git a/src/util/os_installation.c b/src/util/os_installation.c index 0eab118fe..757dba4b6 100644 --- a/src/util/os_installation.c +++ b/src/util/os_installation.c @@ -394,7 +394,7 @@ os_get_taler_path () if (NULL != (ret = get_path_from_proc_maps ())) return ret; /* try path *first*, before /proc/exe, as /proc/exe can be wrong */ - if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd"))) + if (NULL != (ret = get_path_from_PATH ("taler-exchange-httpd"))) return ret; if (NULL != (ret = get_path_from_proc_exe ())) return ret; @@ -409,7 +409,7 @@ os_get_taler_path () if (NULL != (ret = get_path_from_NSGetExecutablePath ())) return ret; #endif - if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd"))) + if (NULL != (ret = get_path_from_PATH ("taler-exchange-httpd"))) return ret; /* other attempts here */ LOG (GNUNET_ERROR_TYPE_ERROR, diff --git a/src/util/wireformats.c b/src/util/wireformats.c index cd5a9c3d4..a69e8a093 100644 --- a/src/util/wireformats.c +++ b/src/util/wireformats.c @@ -421,7 +421,7 @@ TALER_json_validate_wireformat (const char **allowed, if (NULL == allowed[i]) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Wireformat `%s' does not match mint's allowed formats\n", + "Wireformat `%s' does not match exchange's allowed formats\n", stype); return GNUNET_NO; } diff --git a/src/wire/plugin_wire_sepa.c b/src/wire/plugin_wire_sepa.c index 00d19d4b0..4d902f962 100644 --- a/src/wire/plugin_wire_sepa.c +++ b/src/wire/plugin_wire_sepa.c @@ -501,12 +501,12 @@ libtaler_plugin_wire_sepa_init (void *cls) sc = GNUNET_new (struct SepaClosure); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", + "exchange", "CURRENCY", &sc->currency)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", + "exchange", "CURRENCY"); GNUNET_free (sc); return NULL; diff --git a/src/wire/plugin_wire_template.c b/src/wire/plugin_wire_template.c index baf0ee7d5..2e9512e57 100644 --- a/src/wire/plugin_wire_template.c +++ b/src/wire/plugin_wire_template.c @@ -197,12 +197,12 @@ libtaler_plugin_wire_template_init (void *cls) } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "mint", + "exchange", "CURRENCY", &tc->currency)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "mint", + "exchange", "CURRENCY"); GNUNET_free (tc->bank_uri); GNUNET_free (tc); diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c index 8a6f98ea2..2f679bbaa 100644 --- a/src/wire/plugin_wire_test.c +++ b/src/wire/plugin_wire_test.c @@ -553,12 +553,12 @@ libtaler_plugin_wire_test_init (void *cls) tc = GNUNET_new (struct TestClosure); 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 (uri); GNUNET_free (tc); diff --git a/src/wire/test_sepa_wireformat.c b/src/wire/test_sepa_wireformat.c index edbe5bc45..5081cbe86 100644 --- a/src/wire/test_sepa_wireformat.c +++ b/src/wire/test_sepa_wireformat.c @@ -77,7 +77,7 @@ main(int argc, NULL); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, - "mint", + "exchange", "currency", "EUR"); plugin = TALER_WIRE_plugin_load (cfg, |