summaryrefslogtreecommitdiff
path: root/src/exchangedb
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchangedb')
-rw-r--r--src/exchangedb/.gitignore7
-rw-r--r--src/exchangedb/0002-account_merges.sql18
-rw-r--r--src/exchangedb/0002-age_withdraw.sql157
-rw-r--r--src/exchangedb/0002-aggregation_tracking.sql19
-rw-r--r--src/exchangedb/0002-aggregation_transient.sql9
-rw-r--r--src/exchangedb/0002-aml_history.sql (renamed from src/exchangedb/0003-aml_history.sql)34
-rw-r--r--src/exchangedb/0002-aml_staff.sql (renamed from src/exchangedb/0003-aml_staff.sql)2
-rw-r--r--src/exchangedb/0002-aml_status.sql (renamed from src/exchangedb/0003-aml_status.sql)18
-rw-r--r--src/exchangedb/0002-auditors.sql4
-rw-r--r--src/exchangedb/0002-batch_deposits.sql172
-rw-r--r--src/exchangedb/0002-close_requests.sql59
-rw-r--r--src/exchangedb/0002-coin_deposits.sql157
-rw-r--r--src/exchangedb/0002-coin_history.sql138
-rw-r--r--src/exchangedb/0002-contracts.sql8
-rw-r--r--src/exchangedb/0002-cs_nonce_locks.sql6
-rw-r--r--src/exchangedb/0002-denominations.sql15
-rw-r--r--src/exchangedb/0002-deposits.sql419
-rw-r--r--src/exchangedb/0002-extensions.sql2
-rw-r--r--src/exchangedb/0002-global_fee.sql9
-rw-r--r--src/exchangedb/0002-history_requests.sql53
-rw-r--r--src/exchangedb/0002-known_coins.sql15
-rw-r--r--src/exchangedb/0002-kyc_attributes.sql (renamed from src/exchangedb/0003-kyc_attributes.sql)50
-rw-r--r--src/exchangedb/0002-legitimization_processes.sql34
-rw-r--r--src/exchangedb/0002-legitimization_requirements.sql15
-rw-r--r--src/exchangedb/0002-partner_accounts.sql2
-rw-r--r--src/exchangedb/0002-partners.sql5
-rw-r--r--src/exchangedb/0002-policy_details.sql194
-rw-r--r--src/exchangedb/0002-policy_fulfillments.sql100
-rw-r--r--src/exchangedb/0002-prewire.sql24
-rw-r--r--src/exchangedb/0002-profit_drains.sql9
-rw-r--r--src/exchangedb/0002-purse_actions.sql (renamed from src/exchangedb/0003-purse_actions.sql)10
-rw-r--r--src/exchangedb/0002-purse_decision.sql65
-rw-r--r--src/exchangedb/0002-purse_deletion.sql110
-rw-r--r--src/exchangedb/0002-purse_deposits.sql58
-rw-r--r--src/exchangedb/0002-purse_merges.sql23
-rw-r--r--src/exchangedb/0002-purse_requests.sql32
-rw-r--r--src/exchangedb/0002-recoup.sql49
-rw-r--r--src/exchangedb/0002-recoup_refresh.sql74
-rw-r--r--src/exchangedb/0002-refresh_commitments.sql51
-rw-r--r--src/exchangedb/0002-refresh_revealed_coins.sql16
-rw-r--r--src/exchangedb/0002-refresh_transfer_keys.sql10
-rw-r--r--src/exchangedb/0002-refunds.sql61
-rw-r--r--src/exchangedb/0002-reserve_history.sql138
-rw-r--r--src/exchangedb/0002-reserves.sql24
-rw-r--r--src/exchangedb/0002-reserves_close.sql54
-rw-r--r--src/exchangedb/0002-reserves_in.sql70
-rw-r--r--src/exchangedb/0002-reserves_open_deposits.sql49
-rw-r--r--src/exchangedb/0002-reserves_open_requests.sql53
-rw-r--r--src/exchangedb/0002-reserves_out.sql117
-rw-r--r--src/exchangedb/0002-revolving_work_shards.sql2
-rw-r--r--src/exchangedb/0002-wad_in_entries.sql35
-rw-r--r--src/exchangedb/0002-wad_out_entries.sql31
-rw-r--r--src/exchangedb/0002-wads_in.sql13
-rw-r--r--src/exchangedb/0002-wads_out.sql15
-rw-r--r--src/exchangedb/0002-wire_accounts.sql13
-rw-r--r--src/exchangedb/0002-wire_fee.sql8
-rw-r--r--src/exchangedb/0002-wire_out.sql13
-rw-r--r--src/exchangedb/0002-wire_targets.sql8
-rw-r--r--src/exchangedb/0002-work_shards.sql2
-rw-r--r--src/exchangedb/0003-purse_deletion.sql88
-rw-r--r--src/exchangedb/0003-wire_accounts.sql25
-rw-r--r--src/exchangedb/0003-withdraw_age_commitments.sql149
-rw-r--r--src/exchangedb/0003-withdraw_age_reveals.sql138
-rw-r--r--src/exchangedb/0004-refunds.sql35
-rw-r--r--src/exchangedb/Makefile.am58
-rw-r--r--src/exchangedb/auditor-triggers-0001.sql (renamed from src/exchangedb/shard-0001.sql.in)26
-rw-r--r--src/exchangedb/bench_db.c12
-rw-r--r--src/exchangedb/drop.sql18
-rw-r--r--src/exchangedb/exchange-0001.sql29
-rw-r--r--src/exchangedb/exchange-0002.sql.in51
-rw-r--r--src/exchangedb/exchange-0003.sql.in9
-rw-r--r--src/exchangedb/exchange-0004.sql.in (renamed from src/exchangedb/shard-0002.sql.in)15
-rw-r--r--src/exchangedb/exchange_do_age_withdraw.sql165
-rw-r--r--src/exchangedb/exchange_do_amount_specific.sql92
-rw-r--r--src/exchangedb/exchange_do_batch2_reserves_in_insert.sql184
-rw-r--r--src/exchangedb/exchange_do_batch4_reserves_in_insert.sql285
-rw-r--r--src/exchangedb/exchange_do_batch8_reserves_in_insert.sql507
-rw-r--r--src/exchangedb/exchange_do_batch_coin_known.sql469
-rw-r--r--src/exchangedb/exchange_do_batch_reserves_in_insert.sql119
-rw-r--r--src/exchangedb/exchange_do_batch_reserves_update.sql25
-rw-r--r--src/exchangedb/exchange_do_batch_withdraw.sql92
-rw-r--r--src/exchangedb/exchange_do_batch_withdraw_insert.sql19
-rw-r--r--src/exchangedb/exchange_do_deposit.sql229
-rw-r--r--src/exchangedb/exchange_do_expire_purse.sql27
-rw-r--r--src/exchangedb/exchange_do_gc.sql78
-rw-r--r--src/exchangedb/exchange_do_get_ready_deposit.sql69
-rw-r--r--src/exchangedb/exchange_do_history_request.sql85
-rw-r--r--src/exchangedb/exchange_do_insert_aml_decision.sql67
-rw-r--r--src/exchangedb/exchange_do_insert_aml_officer.sql4
-rw-r--r--src/exchangedb/exchange_do_insert_kyc_attributes.sql114
-rw-r--r--src/exchangedb/exchange_do_insert_or_update_policy_details.sql100
-rw-r--r--src/exchangedb/exchange_do_melt.sql32
-rw-r--r--src/exchangedb/exchange_do_purse_delete.sql13
-rw-r--r--src/exchangedb/exchange_do_purse_deposit.sql99
-rw-r--r--src/exchangedb/exchange_do_purse_merge.sql118
-rw-r--r--src/exchangedb/exchange_do_recoup_by_reserve.sql35
-rw-r--r--src/exchangedb/exchange_do_recoup_to_coin.sql43
-rw-r--r--src/exchangedb/exchange_do_recoup_to_reserve.sql64
-rw-r--r--src/exchangedb/exchange_do_refund.sql102
-rw-r--r--src/exchangedb/exchange_do_refund_by_coin.sql94
-rw-r--r--src/exchangedb/exchange_do_reserve_open.sql150
-rw-r--r--src/exchangedb/exchange_do_reserve_open_deposit.sql27
-rw-r--r--src/exchangedb/exchange_do_reserve_purse.sql29
-rw-r--r--src/exchangedb/exchange_do_reserves_in_insert.sql122
-rw-r--r--src/exchangedb/exchange_do_select_deposits_missing_wire.sql73
-rw-r--r--src/exchangedb/exchange_do_select_justification_for_missing_wire.sql102
-rw-r--r--src/exchangedb/exchange_do_withdraw.sql199
-rw-r--r--src/exchangedb/exchangedb-postgres.conf4
-rw-r--r--src/exchangedb/exchangedb_accounts.c33
-rwxr-xr-xsrc/exchangedb/perf-exchangedb-reserves-in-insert-postgres210
-rw-r--r--src/exchangedb/perf_deposits_get_ready.c118
-rw-r--r--src/exchangedb/perf_get_link_data.c17
-rw-r--r--src/exchangedb/perf_reserves_in_insert.c15
-rw-r--r--src/exchangedb/perf_select_refunds_by_coin.c115
-rw-r--r--src/exchangedb/pg_abort_shard.h5
-rw-r--r--src/exchangedb/pg_add_denomination_key.c35
-rw-r--r--src/exchangedb/pg_add_policy_fulfillment_proof.c41
-rw-r--r--src/exchangedb/pg_aggregate.c138
-rw-r--r--src/exchangedb/pg_batch_ensure_coin_known.c462
-rw-r--r--src/exchangedb/pg_batch_ensure_coin_known.h47
-rw-r--r--src/exchangedb/pg_begin_revolving_shard.c36
-rw-r--r--src/exchangedb/pg_begin_revolving_shard.h9
-rw-r--r--src/exchangedb/pg_begin_shard.h8
-rw-r--r--src/exchangedb/pg_commit.c2
-rw-r--r--src/exchangedb/pg_complete_shard.h5
-rw-r--r--src/exchangedb/pg_count_known_coins.c4
-rw-r--r--src/exchangedb/pg_count_known_coins.h2
-rw-r--r--src/exchangedb/pg_create_aggregation_transient.c24
-rw-r--r--src/exchangedb/pg_create_tables.c1
-rw-r--r--src/exchangedb/pg_delete_aggregation_transient.c2
-rw-r--r--src/exchangedb/pg_delete_shard_locks.c1
-rw-r--r--src/exchangedb/pg_do_age_withdraw.c108
-rw-r--r--src/exchangedb/pg_do_age_withdraw.h57
-rw-r--r--src/exchangedb/pg_do_batch_withdraw.c23
-rw-r--r--src/exchangedb/pg_do_batch_withdraw.h8
-rw-r--r--src/exchangedb/pg_do_batch_withdraw_insert.c12
-rw-r--r--src/exchangedb/pg_do_batch_withdraw_insert.h2
-rw-r--r--src/exchangedb/pg_do_deposit.c105
-rw-r--r--src/exchangedb/pg_do_deposit.h17
-rw-r--r--src/exchangedb/pg_do_melt.c6
-rw-r--r--src/exchangedb/pg_do_purse_deposit.c10
-rw-r--r--src/exchangedb/pg_do_purse_merge.c1
-rw-r--r--src/exchangedb/pg_do_recoup.c3
-rw-r--r--src/exchangedb/pg_do_recoup.h2
-rw-r--r--src/exchangedb/pg_do_recoup_refresh.c2
-rw-r--r--src/exchangedb/pg_do_recoup_refresh.h3
-rw-r--r--src/exchangedb/pg_do_refund.c15
-rw-r--r--src/exchangedb/pg_do_reserve_open.c42
-rw-r--r--src/exchangedb/pg_do_reserve_open.h2
-rw-r--r--src/exchangedb/pg_do_reserve_purse.c9
-rw-r--r--src/exchangedb/pg_do_withdraw.c86
-rw-r--r--src/exchangedb/pg_do_withdraw.h53
-rw-r--r--src/exchangedb/pg_drain_kyc_alert.c4
-rw-r--r--src/exchangedb/pg_drain_kyc_alert.h2
-rw-r--r--src/exchangedb/pg_ensure_coin_known.c50
-rw-r--r--src/exchangedb/pg_ensure_coin_known.h6
-rw-r--r--src/exchangedb/pg_event_listen.c8
-rw-r--r--src/exchangedb/pg_event_listen.h6
-rw-r--r--src/exchangedb/pg_event_listen_cancel.c3
-rw-r--r--src/exchangedb/pg_event_notify.c6
-rw-r--r--src/exchangedb/pg_event_notify.h4
-rw-r--r--src/exchangedb/pg_find_aggregation_transient.c5
-rw-r--r--src/exchangedb/pg_gc.h1
-rw-r--r--src/exchangedb/pg_get_age_withdraw.c119
-rw-r--r--src/exchangedb/pg_get_age_withdraw.h45
-rw-r--r--src/exchangedb/pg_get_coin_denomination.c8
-rw-r--r--src/exchangedb/pg_get_coin_transactions.c519
-rw-r--r--src/exchangedb/pg_get_coin_transactions.h27
-rw-r--r--src/exchangedb/pg_get_denomination_info.c20
-rw-r--r--src/exchangedb/pg_get_denomination_revocation.c18
-rw-r--r--src/exchangedb/pg_get_denomination_revocation.h1
-rw-r--r--src/exchangedb/pg_get_drain_profit.c4
-rw-r--r--src/exchangedb/pg_get_expired_reserves.c8
-rw-r--r--src/exchangedb/pg_get_extension_manifest.c9
-rw-r--r--src/exchangedb/pg_get_extension_manifest.h3
-rw-r--r--src/exchangedb/pg_get_global_fee.c51
-rw-r--r--src/exchangedb/pg_get_global_fee.h14
-rw-r--r--src/exchangedb/pg_get_global_fees.c20
-rw-r--r--src/exchangedb/pg_get_global_fees.h3
-rw-r--r--src/exchangedb/pg_get_known_coin.c8
-rw-r--r--src/exchangedb/pg_get_known_coin.h2
-rw-r--r--src/exchangedb/pg_get_link_data.c136
-rw-r--r--src/exchangedb/pg_get_melt.c22
-rw-r--r--src/exchangedb/pg_get_melt.h4
-rw-r--r--src/exchangedb/pg_get_old_coin_by_h_blind.c3
-rw-r--r--src/exchangedb/pg_get_old_coin_by_h_blind.h1
-rw-r--r--src/exchangedb/pg_get_pending_kyc_requirement_process.c66
-rw-r--r--src/exchangedb/pg_get_pending_kyc_requirement_process.h (renamed from src/exchangedb/pg_insert_deposit.h)31
-rw-r--r--src/exchangedb/pg_get_policy_details.c1
-rw-r--r--src/exchangedb/pg_get_purse_deposit.c19
-rw-r--r--src/exchangedb/pg_get_purse_request.c10
-rw-r--r--src/exchangedb/pg_get_ready_deposit.c87
-rw-r--r--src/exchangedb/pg_get_ready_deposit.h6
-rw-r--r--src/exchangedb/pg_get_refresh_reveal.c17
-rw-r--r--src/exchangedb/pg_get_refresh_reveal.h4
-rw-r--r--src/exchangedb/pg_get_reserve_balance.c10
-rw-r--r--src/exchangedb/pg_get_reserve_balance.h2
-rw-r--r--src/exchangedb/pg_get_reserve_by_h_blind.c2
-rw-r--r--src/exchangedb/pg_get_reserve_history.c854
-rw-r--r--src/exchangedb/pg_get_reserve_history.h44
-rw-r--r--src/exchangedb/pg_get_signature_for_known_coin.c (renamed from src/exchangedb/pg_insert_history_request.c)53
-rw-r--r--src/exchangedb/pg_get_signature_for_known_coin.h43
-rw-r--r--src/exchangedb/pg_get_unfinished_close_requests.c3
-rw-r--r--src/exchangedb/pg_get_wire_accounts.c66
-rw-r--r--src/exchangedb/pg_get_wire_accounts.h2
-rw-r--r--src/exchangedb/pg_get_wire_fee.c41
-rw-r--r--src/exchangedb/pg_get_wire_fee.h10
-rw-r--r--src/exchangedb/pg_get_wire_fees.c13
-rw-r--r--src/exchangedb/pg_get_wire_fees.h4
-rw-r--r--src/exchangedb/pg_get_wire_hash_for_contract.c81
-rw-r--r--src/exchangedb/pg_get_wire_hash_for_contract.h46
-rw-r--r--src/exchangedb/pg_get_withdraw_info.c10
-rw-r--r--src/exchangedb/pg_have_deposit2.c45
-rw-r--r--src/exchangedb/pg_helper.h15
-rw-r--r--src/exchangedb/pg_inject_auditor_triggers.c57
-rw-r--r--src/exchangedb/pg_inject_auditor_triggers.h (renamed from src/exchangedb/pg_insert_aggregation_tracking.h)26
-rw-r--r--src/exchangedb/pg_insert_aggregation_tracking.c54
-rw-r--r--src/exchangedb/pg_insert_aml_decision.c36
-rw-r--r--src/exchangedb/pg_insert_aml_decision.h4
-rw-r--r--src/exchangedb/pg_insert_auditor.c10
-rw-r--r--src/exchangedb/pg_insert_auditor.h6
-rw-r--r--src/exchangedb/pg_insert_close_request.c14
-rw-r--r--src/exchangedb/pg_insert_contract.c30
-rw-r--r--src/exchangedb/pg_insert_denomination_info.c32
-rw-r--r--src/exchangedb/pg_insert_denomination_revocation.c2
-rw-r--r--src/exchangedb/pg_insert_deposit.c106
-rw-r--r--src/exchangedb/pg_insert_drain_profit.c11
-rw-r--r--src/exchangedb/pg_insert_global_fee.c52
-rw-r--r--src/exchangedb/pg_insert_global_fee.h12
-rw-r--r--src/exchangedb/pg_insert_history_request.h53
-rw-r--r--src/exchangedb/pg_insert_kyc_attributes.c79
-rw-r--r--src/exchangedb/pg_insert_kyc_attributes.h27
-rw-r--r--src/exchangedb/pg_insert_kyc_failure.c82
-rw-r--r--src/exchangedb/pg_insert_kyc_failure.h (renamed from src/exchangedb/pg_update_kyc_attributes.h)33
-rw-r--r--src/exchangedb/pg_insert_kyc_requirement_for_account.c9
-rw-r--r--src/exchangedb/pg_insert_kyc_requirement_for_account.h3
-rw-r--r--src/exchangedb/pg_insert_kyc_requirement_process.c12
-rw-r--r--src/exchangedb/pg_insert_kyc_requirement_process.h1
-rw-r--r--src/exchangedb/pg_insert_partner.c8
-rw-r--r--src/exchangedb/pg_insert_partner.h12
-rw-r--r--src/exchangedb/pg_insert_purse_request.c14
-rw-r--r--src/exchangedb/pg_insert_records_by_table.c651
-rw-r--r--src/exchangedb/pg_insert_refund.c25
-rw-r--r--src/exchangedb/pg_insert_reserve_closed.c33
-rw-r--r--src/exchangedb/pg_insert_reserve_open_deposit.c5
-rw-r--r--src/exchangedb/pg_insert_wire.c25
-rw-r--r--src/exchangedb/pg_insert_wire.h17
-rw-r--r--src/exchangedb/pg_insert_wire_fee.c38
-rw-r--r--src/exchangedb/pg_insert_wire_fee.h8
-rw-r--r--src/exchangedb/pg_iterate_active_auditors.h3
-rw-r--r--src/exchangedb/pg_iterate_active_signkeys.h2
-rw-r--r--src/exchangedb/pg_iterate_auditor_denominations.h1
-rw-r--r--src/exchangedb/pg_iterate_denomination_info.c16
-rw-r--r--src/exchangedb/pg_iterate_denomination_info.h2
-rw-r--r--src/exchangedb/pg_iterate_denominations.c23
-rw-r--r--src/exchangedb/pg_iterate_denominations.h2
-rw-r--r--src/exchangedb/pg_iterate_reserve_close_info.c3
-rw-r--r--src/exchangedb/pg_kyc_provider_account_lookup.c5
-rw-r--r--src/exchangedb/pg_kyc_provider_account_lookup.h1
-rw-r--r--src/exchangedb/pg_lookup_auditor_status.c2
-rw-r--r--src/exchangedb/pg_lookup_auditor_timestamp.c2
-rw-r--r--src/exchangedb/pg_lookup_denomination_key.c16
-rw-r--r--src/exchangedb/pg_lookup_global_fee_by_time.c9
-rw-r--r--src/exchangedb/pg_lookup_global_fee_by_time.h1
-rw-r--r--src/exchangedb/pg_lookup_kyc_process_by_account.c8
-rw-r--r--src/exchangedb/pg_lookup_kyc_process_by_account.h1
-rw-r--r--src/exchangedb/pg_lookup_kyc_requirement_by_row.c21
-rw-r--r--src/exchangedb/pg_lookup_kyc_requirement_by_row.h3
-rw-r--r--src/exchangedb/pg_lookup_records_by_table.c939
-rw-r--r--src/exchangedb/pg_lookup_serial_by_table.c65
-rw-r--r--src/exchangedb/pg_lookup_signing_key.c1
-rw-r--r--src/exchangedb/pg_lookup_transfer_by_deposit.c110
-rw-r--r--src/exchangedb/pg_lookup_transfer_by_deposit.h4
-rw-r--r--src/exchangedb/pg_lookup_wire_fee_by_time.c6
-rw-r--r--src/exchangedb/pg_lookup_wire_timestamp.c4
-rw-r--r--src/exchangedb/pg_lookup_wire_timestamp.h2
-rw-r--r--src/exchangedb/pg_lookup_wire_transfer.c21
-rw-r--r--src/exchangedb/pg_persist_policy_details.c17
-rw-r--r--src/exchangedb/pg_persist_policy_details.h2
-rw-r--r--src/exchangedb/pg_profit_drains_get_pending.c5
-rw-r--r--src/exchangedb/pg_profit_drains_set_finished.c16
-rw-r--r--src/exchangedb/pg_release_revolving_shard.c6
-rw-r--r--src/exchangedb/pg_release_revolving_shard.h4
-rw-r--r--src/exchangedb/pg_reserves_get.c10
-rw-r--r--src/exchangedb/pg_reserves_get_origin.c2
-rw-r--r--src/exchangedb/pg_reserves_in_insert.c1030
-rw-r--r--src/exchangedb/pg_reserves_in_insert.h2
-rw-r--r--src/exchangedb/pg_reserves_update.c10
-rw-r--r--src/exchangedb/pg_rollback.c2
-rw-r--r--src/exchangedb/pg_select_account_merges_above_serial_id.c6
-rw-r--r--src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c6
-rw-r--r--src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h1
-rw-r--r--src/exchangedb/pg_select_aggregation_transient.c5
-rw-r--r--src/exchangedb/pg_select_aggregations_above_serial.c137
-rw-r--r--src/exchangedb/pg_select_aggregations_above_serial.h47
-rw-r--r--src/exchangedb/pg_select_aml_history.c3
-rw-r--r--src/exchangedb/pg_select_aml_process.c6
-rw-r--r--src/exchangedb/pg_select_aml_threshold.c70
-rw-r--r--src/exchangedb/pg_select_aml_threshold.h48
-rw-r--r--src/exchangedb/pg_select_auditor_denom_sig.c1
-rw-r--r--src/exchangedb/pg_select_batch_deposits_missing_wire.c144
-rw-r--r--src/exchangedb/pg_select_batch_deposits_missing_wire.h (renamed from src/exchangedb/pg_select_history_requests_above_serial_id.h)24
-rw-r--r--src/exchangedb/pg_select_coin_deposits_above_serial_id.c (renamed from src/exchangedb/pg_select_deposits_above_serial_id.c)82
-rw-r--r--src/exchangedb/pg_select_coin_deposits_above_serial_id.h (renamed from src/exchangedb/pg_select_deposits_above_serial_id.h)6
-rw-r--r--src/exchangedb/pg_select_contract.c26
-rw-r--r--src/exchangedb/pg_select_contract.h8
-rw-r--r--src/exchangedb/pg_select_contract_by_purse.c2
-rw-r--r--src/exchangedb/pg_select_deposits_missing_wire.c176
-rw-r--r--src/exchangedb/pg_select_deposits_missing_wire.h46
-rw-r--r--src/exchangedb/pg_select_history_requests_above_serial_id.c159
-rw-r--r--src/exchangedb/pg_select_justification_for_missing_wire.c89
-rw-r--r--src/exchangedb/pg_select_justification_for_missing_wire.h49
-rw-r--r--src/exchangedb/pg_select_kyc_attributes.c7
-rw-r--r--src/exchangedb/pg_select_merge_amounts_for_kyc_check.c7
-rw-r--r--src/exchangedb/pg_select_purse.c16
-rw-r--r--src/exchangedb/pg_select_purse.h5
-rw-r--r--src/exchangedb/pg_select_purse_by_merge_pub.c8
-rw-r--r--src/exchangedb/pg_select_purse_decisions_above_serial_id.c4
-rw-r--r--src/exchangedb/pg_select_purse_decisions_above_serial_id.h1
-rw-r--r--src/exchangedb/pg_select_purse_deposits_above_serial_id.c9
-rw-r--r--src/exchangedb/pg_select_purse_deposits_by_purse.c10
-rw-r--r--src/exchangedb/pg_select_purse_merge.c28
-rw-r--r--src/exchangedb/pg_select_purse_merge.h4
-rw-r--r--src/exchangedb/pg_select_purse_merges_above_serial_id.c6
-rw-r--r--src/exchangedb/pg_select_purse_requests_above_serial_id.c3
-rw-r--r--src/exchangedb/pg_select_recoup_above_serial_id.c8
-rw-r--r--src/exchangedb/pg_select_recoup_refresh_above_serial_id.c8
-rw-r--r--src/exchangedb/pg_select_refreshes_above_serial_id.c10
-rw-r--r--src/exchangedb/pg_select_refunds_above_serial_id.c29
-rw-r--r--src/exchangedb/pg_select_refunds_by_coin.c224
-rw-r--r--src/exchangedb/pg_select_refunds_by_coin.h1
-rw-r--r--src/exchangedb/pg_select_reserve_close_info.c6
-rw-r--r--src/exchangedb/pg_select_reserve_closed_above_serial_id.c6
-rw-r--r--src/exchangedb/pg_select_reserve_open_above_serial_id.c3
-rw-r--r--src/exchangedb/pg_select_reserves_in_above_serial_id.c5
-rw-r--r--src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c13
-rw-r--r--src/exchangedb/pg_select_similar_kyc_attributes.c7
-rw-r--r--src/exchangedb/pg_select_wire_out_above_serial_id.c6
-rw-r--r--src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c5
-rw-r--r--src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h1
-rw-r--r--src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c28
-rw-r--r--src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h1
-rw-r--r--src/exchangedb/pg_select_withdrawals_above_serial_id.c9
-rw-r--r--src/exchangedb/pg_select_withdrawals_above_serial_id.h1
-rw-r--r--src/exchangedb/pg_set_extension_manifest.c4
-rw-r--r--src/exchangedb/pg_set_extension_manifest.h2
-rw-r--r--src/exchangedb/pg_set_purse_balance.c9
-rw-r--r--src/exchangedb/pg_setup_wire_target.c2
-rw-r--r--src/exchangedb/pg_setup_wire_target.h2
-rw-r--r--src/exchangedb/pg_start.c3
-rw-r--r--src/exchangedb/pg_store_wire_transfer_out.c10
-rw-r--r--src/exchangedb/pg_template.c2
-rw-r--r--src/exchangedb/pg_template.h2
-rw-r--r--src/exchangedb/pg_trigger_aml_process.c17
-rw-r--r--src/exchangedb/pg_update_aggregation_transient.c15
-rw-r--r--src/exchangedb/pg_update_auditor.c30
-rw-r--r--src/exchangedb/pg_update_auditor.h8
-rw-r--r--src/exchangedb/pg_update_kyc_attributes.c68
-rw-r--r--src/exchangedb/pg_update_kyc_process_by_row.c15
-rw-r--r--src/exchangedb/pg_update_kyc_process_by_row.h2
-rw-r--r--src/exchangedb/pg_update_wire.c39
-rw-r--r--src/exchangedb/pg_update_wire.h18
-rw-r--r--src/exchangedb/pg_wire_prepare_data_get.c10
-rw-r--r--src/exchangedb/pg_wire_prepare_data_get.h7
-rw-r--r--src/exchangedb/pg_wire_prepare_data_insert.c22
-rw-r--r--src/exchangedb/pg_wire_prepare_data_insert.h5
-rw-r--r--src/exchangedb/pg_wire_prepare_data_mark_failed.c2
-rw-r--r--src/exchangedb/pg_wire_prepare_data_mark_failed.h1
-rw-r--r--src/exchangedb/pg_wire_prepare_data_mark_finished.c10
-rw-r--r--src/exchangedb/pg_wire_prepare_data_mark_finished.h1
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c111
-rw-r--r--src/exchangedb/procedures.sql.in16
-rw-r--r--src/exchangedb/spi/Makefile9
-rw-r--r--src/exchangedb/spi/README.md37
-rw-r--r--src/exchangedb/spi/own_test.c873
-rw-r--r--src/exchangedb/spi/own_test.control4
-rw-r--r--src/exchangedb/spi/own_test.sql201
-rw-r--r--src/exchangedb/spi/perf_own_test.c25
-rw-r--r--src/exchangedb/spi/pg_aggregate.c411
-rwxr-xr-xsrc/exchangedb/test-exchangedb-batch-reserves-in-insert-postgres210
-rwxr-xr-xsrc/exchangedb/test-exchangedb-by-j-postgres210
-rwxr-xr-xsrc/exchangedb/test-exchangedb-populate-link-data-postgres210
-rwxr-xr-xsrc/exchangedb/test-exchangedb-populate-ready-deposit-postgres210
-rwxr-xr-xsrc/exchangedb/test-exchangedb-populate-select-refunds-by-coin-postgres210
-rw-r--r--src/exchangedb/test_exchangedb.c378
-rw-r--r--src/exchangedb/test_exchangedb_by_j.c133
-rwxr-xr-xsrc/exchangedb/test_idempotency.sh12
-rw-r--r--src/exchangedb/versioning.sql3
388 files changed, 13121 insertions, 8302 deletions
diff --git a/src/exchangedb/.gitignore b/src/exchangedb/.gitignore
index 264217a3d..6e67fadb1 100644
--- a/src/exchangedb/.gitignore
+++ b/src/exchangedb/.gitignore
@@ -7,3 +7,10 @@ perf_select_refunds_by_coin-postgres
exchange-0002.sql
procedures.sql
exchange-0003.sql
+perf-exchangedb-reserves-in-insert-postgres
+test-exchangedb-batch-reserves-in-insert-postgres
+test-exchangedb-by-j-postgres
+test-exchangedb-populate-link-data-postgres
+test-exchangedb-populate-ready-deposit-postgres
+test-exchangedb-populate-select-refunds-by-coin-postgres
+exchange-0004.sql
diff --git a/src/exchangedb/0002-account_merges.sql b/src/exchangedb/0002-account_merges.sql
index b1995f204..1dd7e5bf0 100644
--- a/src/exchangedb/0002-account_merges.sql
+++ b/src/exchangedb/0002-account_merges.sql
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_account_merges(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'account_merges';
+ table_name TEXT DEFAULT 'account_merges';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I '
@@ -64,17 +64,23 @@ $$;
CREATE FUNCTION constrain_table_account_merges(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'account_merges';
+ table_name TEXT DEFAULT 'account_merges';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by reserve_pub!?
+ -- Note: this index *may* be useful in
+ -- pg_get_reserve_history depending on how
+ -- smart the DB is when computing the JOIN.
+ -- Removing it MAY boost performance slightly, at
+ -- the expense of trouble if the "merge_by_reserve"
+ -- query planner goes off the rails. Needs benchmarking
+ -- to be sure.
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_reserve_pub '
'ON ' || table_name || ' '
@@ -94,7 +100,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'account_merges';
+ table_name TEXT DEFAULT 'account_merges';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-age_withdraw.sql b/src/exchangedb/0002-age_withdraw.sql
new file mode 100644
index 000000000..87cac7816
--- /dev/null
+++ b/src/exchangedb/0002-age_withdraw.sql
@@ -0,0 +1,157 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+-- @author Özgür Kesim
+
+CREATE FUNCTION create_table_age_withdraw(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'age_withdraw';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I'
+ '(age_withdraw_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
+ ',h_commitment BYTEA NOT NULL CONSTRAINT h_commitment_length CHECK(LENGTH(h_commitment)=64)'
+ ',max_age SMALLINT NOT NULL CONSTRAINT max_age_positive CHECK(max_age>=0)'
+ ',amount_with_fee taler_amount NOT NULL'
+ ',reserve_pub BYTEA NOT NULL CONSTRAINT reserve_pub_length CHECK(LENGTH(reserve_pub)=32)'
+ ',reserve_sig BYTEA NOT NULL CONSTRAINT reserve_sig_length CHECK(LENGTH(reserve_sig)=64)'
+ ',noreveal_index SMALLINT NOT NULL CONSTRAINT noreveal_index_positive CHECK(noreveal_index>=0)'
+ ',h_blind_evs BYTEA[] NOT NULL CONSTRAINT h_blind_evs_length CHECK(cardinality(h_blind_evs)=cardinality(denom_serials))'
+ ',denom_serials INT8[] NOT NULL CONSTRAINT denom_serials_array_length CHECK(cardinality(denom_serials)=cardinality(denom_sigs))'
+ ',denom_sigs BYTEA[] NOT NULL CONSTRAINT denom_sigs_array_length CHECK(cardinality(denom_sigs)=cardinality(denom_serials))'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (reserve_pub)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Commitments made when withdrawing coins with age restriction and the gamma value chosen by the exchange. '
+ 'It also contains the blindly signed coins, their signatures and denominations.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The gamma value chosen by the exchange in the cut-and-choose protocol'
+ ,'noreveal_index'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The maximum age (in years) that the client commits to with this request'
+ ,'max_age'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Commitment made by the client, hash over the various client inputs in the cut-and-choose protocol'
+ ,'h_commitment'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Reference to the public key of the reserve from which the coins are going to be withdrawn'
+ ,'reserve_pub'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Signature of the reserve''s private key over the age-withdraw request'
+ ,'reserve_sig'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Array of references to the denominations'
+ ,'denom_serials'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Array of the blinded envelopes of the chosen fresh coins, with value as given by the denomination in the corresponding slot in denom_serials'
+ ,'h_blind_evs'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Array of signatures over each blinded envelope'
+ ,'denom_sigs'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+
+CREATE FUNCTION constrain_table_age_withdraw(
+ IN partition_suffix TEXT
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'age_withdraw';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD PRIMARY KEY (h_commitment);'
+ );
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_h_commitment_reserve_pub_key'
+ ' UNIQUE (h_commitment, reserve_pub);'
+ );
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_age_withdraw_id_key'
+ ' UNIQUE (age_withdraw_id);'
+ );
+END
+$$;
+
+
+CREATE FUNCTION foreign_table_age_withdraw()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'age_withdraw';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub'
+ ' FOREIGN KEY (reserve_pub)'
+ ' REFERENCES reserves(reserve_pub) ON DELETE CASCADE;'
+ );
+END
+$$;
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+VALUES
+ ('age_withdraw', 'exchange-0002', 'create', TRUE ,FALSE),
+ ('age_withdraw', 'exchange-0002', 'constrain',TRUE ,FALSE),
+ ('age_withdraw', 'exchange-0002', 'foreign', TRUE ,FALSE);
+
diff --git a/src/exchangedb/0002-aggregation_tracking.sql b/src/exchangedb/0002-aggregation_tracking.sql
index f6135c5ac..d07960247 100644
--- a/src/exchangedb/0002-aggregation_tracking.sql
+++ b/src/exchangedb/0002-aggregation_tracking.sql
@@ -15,22 +15,22 @@
--
CREATE FUNCTION create_table_aggregation_tracking(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aggregation_tracking';
+ table_name TEXT DEFAULT 'aggregation_tracking';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
'(aggregation_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
- ',deposit_serial_id INT8 PRIMARY KEY'
+ ',batch_deposit_serial_id INT8 PRIMARY KEY'
',wtid_raw BYTEA NOT NULL'
') %s ;'
,table_name
- ,'PARTITION BY HASH (deposit_serial_id)'
+ ,'PARTITION BY HASH (batch_deposit_serial_id)'
,partition_suffix
);
PERFORM comment_partitioned_table(
@@ -49,13 +49,13 @@ $$;
CREATE FUNCTION constrain_table_aggregation_tracking(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aggregation_tracking';
+ table_name TEXT DEFAULT 'aggregation_tracking';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -81,13 +81,14 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aggregation_tracking';
+ table_name TEXT DEFAULT 'aggregation_tracking';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_foreign_deposit'
- ' FOREIGN KEY (deposit_serial_id) '
- ' REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE' -- FIXME change to coin_pub + deposit_serial_id for more efficient deposit???
+ ' FOREIGN KEY (batch_deposit_serial_id)'
+ ' REFERENCES batch_deposits (batch_deposit_serial_id)'
+ ' ON DELETE CASCADE'
);
END
$$;
diff --git a/src/exchangedb/0002-aggregation_transient.sql b/src/exchangedb/0002-aggregation_transient.sql
index 2d77e63ca..8e46450f0 100644
--- a/src/exchangedb/0002-aggregation_transient.sql
+++ b/src/exchangedb/0002-aggregation_transient.sql
@@ -15,18 +15,17 @@
--
CREATE FUNCTION create_table_aggregation_transient(
- IN shard_suffix VARCHAR DEFAULT NULL
+ IN shard_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aggregation_transient';
+ table_name TEXT DEFAULT 'aggregation_transient';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
- '(amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
+ '(amount taler_amount NOT NULL'
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
',merchant_pub BYTEA CHECK (LENGTH(merchant_pub)=32)'
',exchange_account_section TEXT NOT NULL'
@@ -44,7 +43,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Sum of all of the aggregated deposits (without deposit fees)'
- ,'amount_val'
+ ,'amount'
,table_name
,shard_suffix
);
diff --git a/src/exchangedb/0003-aml_history.sql b/src/exchangedb/0002-aml_history.sql
index 36c0b3865..af81be9d8 100644
--- a/src/exchangedb/0003-aml_history.sql
+++ b/src/exchangedb/0002-aml_history.sql
@@ -15,23 +15,24 @@
--
CREATE OR REPLACE FUNCTION create_table_aml_history(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aml_history';
+ table_name TEXT DEFAULT 'aml_history';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
'(aml_history_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_payto BYTEA CHECK (LENGTH(h_payto)=32)'
- ',new_threshold_val INT8 NOT NULL DEFAULT(0)'
- ',new_threshold_frac INT4 NOT NULL DEFAULT(0)'
+ ',new_threshold taler_amount NOT NULL DEFAULT(0,0)'
',new_status INT4 NOT NULL DEFAULT(0)'
',decision_time INT8 NOT NULL DEFAULT(0)'
- ',justification VARCHAR NOT NULL'
+ ',justification TEXT NOT NULL'
+ ',kyc_requirements TEXT'
+ ',kyc_req_row INT8 NOT NULL DEFAULT(0)'
',decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)'
',decider_sig BYTEA CHECK (LENGTH(decider_sig)=64)'
') %s ;'
@@ -52,7 +53,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'new monthly inbound transaction limit below which we are OK'
- ,'new_threshold_val'
+ ,'new_threshold'
,table_name
,partition_suffix
);
@@ -81,6 +82,18 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
+ 'Additional KYC requirements imposed by the AML staff member. Serialized JSON array of strings.'
+ ,'kyc_requirements'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Row in the KYC table for this KYC requirement, 0 for none.'
+ ,'kyc_req_row'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
'Signature key of the staff member affirming the AML decision; of type AML_DECISION'
,'decider_sig'
,table_name
@@ -93,13 +106,13 @@ COMMENT ON FUNCTION create_table_aml_history
CREATE OR REPLACE FUNCTION constrain_table_aml_history(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aml_history';
+ table_name TEXT DEFAULT 'aml_history';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -114,7 +127,6 @@ BEGIN
);
END $$;
--- FIXME: also have INSERT on AML decisions to update AML status!
INSERT INTO exchange_tables
(name
@@ -124,12 +136,12 @@ INSERT INTO exchange_tables
,by_range)
VALUES
('aml_history'
- ,'exchange-0003'
+ ,'exchange-0002'
,'create'
,TRUE
,FALSE),
('aml_history'
- ,'exchange-0003'
+ ,'exchange-0002'
,'constrain'
,TRUE
,FALSE);
diff --git a/src/exchangedb/0003-aml_staff.sql b/src/exchangedb/0002-aml_staff.sql
index 00f60985a..cec18c62b 100644
--- a/src/exchangedb/0003-aml_staff.sql
+++ b/src/exchangedb/0002-aml_staff.sql
@@ -19,7 +19,7 @@ CREATE TABLE aml_staff
(aml_staff_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,decider_pub BYTEA PRIMARY KEY CHECK (LENGTH(decider_pub)=32)
,master_sig BYTEA CHECK (LENGTH(master_sig)=64)
- ,decider_name VARCHAR NOT NULL
+ ,decider_name TEXT NOT NULL
,is_active BOOLEAN NOT NULL
,read_only BOOLEAN NOT NULL
,last_change INT8 NOT NULL
diff --git a/src/exchangedb/0003-aml_status.sql b/src/exchangedb/0002-aml_status.sql
index c0683c0d8..a8b567a82 100644
--- a/src/exchangedb/0003-aml_status.sql
+++ b/src/exchangedb/0002-aml_status.sql
@@ -15,21 +15,21 @@
--
CREATE OR REPLACE FUNCTION create_table_aml_status(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aml_status';
+ table_name TEXT DEFAULT 'aml_status';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
'(aml_status_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)'
- ',threshold_val INT8 NOT NULL DEFAULT(0)'
- ',threshold_frac INT4 NOT NULL DEFAULT(0)'
+ ',threshold taler_amount NOT NULL DEFAULT(0,0)'
',status INT4 NOT NULL DEFAULT(0)'
+ ',kyc_requirement INT8 NOT NULL DEFAULT(0)'
') %s ;'
,table_name
,'PARTITION BY HASH (h_payto)'
@@ -48,7 +48,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'monthly inbound transaction limit below which we are OK (if status is 1)'
- ,'threshold_val'
+ ,'threshold'
,table_name
,partition_suffix
);
@@ -65,13 +65,13 @@ COMMENT ON FUNCTION create_table_aml_status
CREATE OR REPLACE FUNCTION constrain_table_aml_status(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'aml_status';
+ table_name TEXT DEFAULT 'aml_status';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -90,12 +90,12 @@ INSERT INTO exchange_tables
,by_range)
VALUES
('aml_status'
- ,'exchange-0003'
+ ,'exchange-0002'
,'create'
,TRUE
,FALSE),
('aml_status'
- ,'exchange-0003'
+ ,'exchange-0002'
,'constrain'
,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-auditors.sql b/src/exchangedb/0002-auditors.sql
index 32ec8446a..76e43b183 100644
--- a/src/exchangedb/0002-auditors.sql
+++ b/src/exchangedb/0002-auditors.sql
@@ -18,8 +18,8 @@
CREATE TABLE auditors
(auditor_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,auditor_pub BYTEA PRIMARY KEY CHECK (LENGTH(auditor_pub)=32)
- ,auditor_name VARCHAR NOT NULL
- ,auditor_url VARCHAR NOT NULL
+ ,auditor_name TEXT NOT NULL
+ ,auditor_url TEXT NOT NULL
,is_active BOOLEAN NOT NULL
,last_change INT8 NOT NULL
);
diff --git a/src/exchangedb/0002-batch_deposits.sql b/src/exchangedb/0002-batch_deposits.sql
new file mode 100644
index 000000000..71a4b4205
--- /dev/null
+++ b/src/exchangedb/0002-batch_deposits.sql
@@ -0,0 +1,172 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE FUNCTION create_table_batch_deposits(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'batch_deposits';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I'
+ '(batch_deposit_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY'
+ ',shard INT8 NOT NULL'
+ ',merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)'
+ ',wallet_timestamp INT8 NOT NULL'
+ ',exchange_timestamp INT8 NOT NULL'
+ ',refund_deadline INT8 NOT NULL'
+ ',wire_deadline INT8 NOT NULL'
+ ',h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)'
+ ',wallet_data_hash BYTEA CHECK (LENGTH(wallet_data_hash)=64) DEFAULT NULL'
+ ',wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16)'
+ ',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
+ ',policy_details_serial_id INT8'
+ ',policy_blocked BOOLEAN NOT NULL DEFAULT FALSE'
+ ',done BOOLEAN NOT NULL DEFAULT FALSE'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (shard)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Information about the contracts for which we have received (batch) deposits.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Used for load sharding in the materialized indices. Should be set based on merchant_pub. 64-bit value because we need an *unsigned* 32-bit value.'
+ ,'shard'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Unsalted hash of the target bank account; also used to lookup the KYC status'
+ ,'wire_target_h_payto'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'hash over data provided by the wallet upon payment to select a more specific contract'
+ ,'wallet_data_hash'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Salt used when hashing the payto://-URI to get the h_wire that was used by the coin deposit signatures; not used to calculate wire_target_h_payto (as that one is unsalted)'
+ ,'wire_salt'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Set to TRUE once we have included this (batch) deposit (and all associated coins) in some aggregate wire transfer to the merchant'
+ ,'done'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'True if the aggregation of the (batch) deposit is currently blocked by some policy extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.'
+ ,'policy_blocked'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'References policy extensions table, NULL if extensions are not used'
+ ,'policy_details_serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+
+CREATE FUNCTION constrain_table_batch_deposits(
+ IN partition_suffix TEXT
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'batch_deposits';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_batch_deposit_serial_id_pkey'
+ ' PRIMARY KEY (batch_deposit_serial_id) '
+ ',ADD CONSTRAINT ' || table_name || '_merchant_pub_h_contract_terms'
+ ' UNIQUE (shard, merchant_pub, h_contract_terms)'
+ );
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || table_name || '_by_ready '
+ 'ON ' || table_name || ' '
+ '(shard ASC'
+ ',wire_deadline ASC'
+ ') WHERE NOT (done OR policy_blocked);'
+ );
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || table_name || '_for_matching '
+ 'ON ' || table_name || ' '
+ '(shard ASC'
+ ',refund_deadline ASC'
+ ',wire_target_h_payto'
+ ') WHERE NOT (done OR policy_blocked);'
+ );
+END
+$$;
+
+CREATE OR REPLACE FUNCTION foreign_table_batch_deposits()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'batch_deposits';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_policy_details'
+ ' FOREIGN KEY (policy_details_serial_id) '
+ ' REFERENCES policy_details (policy_details_serial_id) ON DELETE RESTRICT'
+ );
+END
+$$;
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('batch_deposits'
+ ,'exchange-0002'
+ ,'create'
+ ,TRUE
+ ,FALSE),
+ ('batch_deposits'
+ ,'exchange-0002'
+ ,'constrain'
+ ,TRUE
+ ,FALSE),
+ ('batch_deposits'
+ ,'exchange-0002'
+ ,'foreign'
+ ,TRUE
+ ,FALSE)
+ ;
diff --git a/src/exchangedb/0002-close_requests.sql b/src/exchangedb/0002-close_requests.sql
index 32149b1b0..6a7028095 100644
--- a/src/exchangedb/0002-close_requests.sql
+++ b/src/exchangedb/0002-close_requests.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_close_requests(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'close_requests';
+ table_name TEXT DEFAULT 'close_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -29,11 +29,9 @@ BEGIN
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
',close_timestamp INT8 NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
- ',close_val INT8 NOT NULL'
- ',close_frac INT4 NOT NULL'
- ',close_fee_val INT8 NOT NULL'
- ',close_fee_frac INT4 NOT NULL'
- ',payto_uri VARCHAR NOT NULL'
+ ',close taler_amount NOT NULL'
+ ',close_fee taler_amount NOT NULL'
+ ',payto_uri TEXT NOT NULL'
',done BOOL NOT NULL DEFAULT(FALSE)'
',PRIMARY KEY (reserve_pub,close_timestamp)'
') %s ;'
@@ -60,7 +58,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Balance of the reserve at the time of closing, to be wired to the associated bank account (minus the closing fee)'
- ,'close_val'
+ ,'close'
,table_name
,partition_suffix
);
@@ -74,13 +72,13 @@ END $$;
CREATE FUNCTION constrain_table_close_requests(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'close_requests';
+ table_name TEXT DEFAULT 'close_requests';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -107,7 +105,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'close_requests';
+ table_name TEXT DEFAULT 'close_requests';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -119,6 +117,38 @@ END
$$;
+CREATE OR REPLACE FUNCTION close_requests_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.reserve_pub
+ ,'close_requests'
+ ,NEW.close_request_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION close_requests_insert_trigger()
+ IS 'Automatically generate reserve history entry.';
+
+
+CREATE FUNCTION master_table_close_requests()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER close_requests_on_insert
+ AFTER INSERT
+ ON close_requests
+ FOR EACH ROW EXECUTE FUNCTION close_requests_insert_trigger();
+END $$;
+
+
+
INSERT INTO exchange_tables
(name
,version
@@ -140,4 +170,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('close_requests'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-coin_deposits.sql b/src/exchangedb/0002-coin_deposits.sql
new file mode 100644
index 000000000..c3eef6e5a
--- /dev/null
+++ b/src/exchangedb/0002-coin_deposits.sql
@@ -0,0 +1,157 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE FUNCTION create_table_coin_deposits(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_deposits';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I'
+ '(coin_deposit_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY'
+ ',batch_deposit_serial_id INT8 NOT NULL'
+ ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
+ ',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)'
+ ',amount_with_fee taler_amount NOT NULL'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (coin_pub)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Coins which have been deposited with the respective per-coin signatures.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Link to information about the batch deposit this coin was used for'
+ ,'batch_deposit_serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+
+CREATE FUNCTION constrain_table_coin_deposits(
+ IN partition_suffix TEXT
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_deposits';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_coin_deposit_serial_id_pkey'
+ ' PRIMARY KEY (coin_deposit_serial_id) '
+ ',ADD CONSTRAINT ' || table_name || '_unique_coin_sig'
+ ' UNIQUE (coin_pub, coin_sig)'
+ );
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || table_name || '_by_batch '
+ 'ON ' || table_name || ' '
+ '(batch_deposit_serial_id);'
+ );
+END
+$$;
+
+
+CREATE FUNCTION foreign_table_coin_deposits()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_deposits';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_coin_pub'
+ ' FOREIGN KEY (coin_pub) '
+ ' REFERENCES known_coins (coin_pub) ON DELETE CASCADE'
+ ',ADD CONSTRAINT ' || table_name || '_foreign_batch_deposits_id'
+ ' FOREIGN KEY (batch_deposit_serial_id) '
+ ' REFERENCES batch_deposits (batch_deposit_serial_id) ON DELETE CASCADE'
+ );
+END
+$$;
+
+
+CREATE OR REPLACE FUNCTION coin_deposits_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'coin_deposits'
+ ,NEW.coin_deposit_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION coin_deposits_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_coin_deposits()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER coin_deposits_on_insert
+ AFTER INSERT
+ ON coin_deposits
+ FOR EACH ROW EXECUTE FUNCTION coin_deposits_insert_trigger();
+END $$;
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('coin_deposits'
+ ,'exchange-0002'
+ ,'create'
+ ,TRUE
+ ,FALSE),
+ ('coin_deposits'
+ ,'exchange-0002'
+ ,'constrain'
+ ,TRUE
+ ,FALSE),
+ ('coin_deposits'
+ ,'exchange-0002'
+ ,'foreign'
+ ,TRUE
+ ,FALSE),
+ ('coin_deposits'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
+ ,FALSE)
+ ;
diff --git a/src/exchangedb/0002-coin_history.sql b/src/exchangedb/0002-coin_history.sql
new file mode 100644
index 000000000..9b5efdcb6
--- /dev/null
+++ b/src/exchangedb/0002-coin_history.sql
@@ -0,0 +1,138 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE FUNCTION create_table_coin_history (
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_history';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I'
+ '(coin_history_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY'
+ ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
+ ',table_name TEXT NOT NULL'
+ ',serial_id INT8 NOT NULL'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (coin_pub)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Links to tables with entries that affected the transaction history of a coin.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'For which coin is this a history entry'
+ ,'coin_pub'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'In which table is the history entry'
+ ,'table_name'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Which is the generated serial ID of the entry in the table'
+ ,'serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Monotonic counter, used to generate Etags for caching'
+ ,'coin_history_serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+
+CREATE FUNCTION constrain_table_coin_history(
+ IN partition_suffix TEXT
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_history';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_coin_history_serial_id_pkey'
+ ' PRIMARY KEY (coin_history_serial_id) '
+ ',ADD CONSTRAINT ' || table_name || '_coin_entry_key'
+ ' UNIQUE (coin_pub, table_name, serial_id)'
+ );
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || table_name || '_coin_by_time'
+ ' ON ' || table_name || ' '
+ '(coin_pub'
+ ',coin_history_serial_id DESC'
+ ');'
+ );
+END
+$$;
+
+
+CREATE FUNCTION foreign_table_coin_history()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'coin_history';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_coin_pub'
+ ' FOREIGN KEY (coin_pub) '
+ ' REFERENCES known_coins (coin_pub) ON DELETE CASCADE'
+ );
+END
+$$;
+
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('coin_history'
+ ,'exchange-0002'
+ ,'create'
+ ,TRUE
+ ,FALSE),
+ ('coin_history'
+ ,'exchange-0002'
+ ,'constrain'
+ ,TRUE
+ ,FALSE),
+ ('coin_history'
+ ,'exchange-0002'
+ ,'foreign'
+ ,TRUE
+ ,FALSE)
+ ;
diff --git a/src/exchangedb/0002-contracts.sql b/src/exchangedb/0002-contracts.sql
index 409653060..c1f92c9aa 100644
--- a/src/exchangedb/0002-contracts.sql
+++ b/src/exchangedb/0002-contracts.sql
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_contracts(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'contracts';
+ table_name TEXT DEFAULT 'contracts';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -72,13 +72,13 @@ $$;
CREATE FUNCTION constrain_table_contracts(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'contracts';
+ table_name TEXT DEFAULT 'contracts';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-cs_nonce_locks.sql b/src/exchangedb/0002-cs_nonce_locks.sql
index 0cb88b3f8..36c0c7a5f 100644
--- a/src/exchangedb/0002-cs_nonce_locks.sql
+++ b/src/exchangedb/0002-cs_nonce_locks.sql
@@ -15,7 +15,7 @@
--
CREATE FUNCTION create_table_cs_nonce_locks(
- partition_suffix VARCHAR DEFAULT NULL
+ partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -60,13 +60,13 @@ $$;
CREATE FUNCTION constrain_table_cs_nonce_locks(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'cs_nonce_locks';
+ table_name TEXT DEFAULT 'cs_nonce_locks';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-denominations.sql b/src/exchangedb/0002-denominations.sql
index d468a3875..a3de2b149 100644
--- a/src/exchangedb/0002-denominations.sql
+++ b/src/exchangedb/0002-denominations.sql
@@ -25,16 +25,11 @@ CREATE TABLE denominations
,expire_withdraw INT8 NOT NULL
,expire_deposit INT8 NOT NULL
,expire_legal INT8 NOT NULL
- ,coin_val INT8 NOT NULL
- ,coin_frac INT4 NOT NULL
- ,fee_withdraw_val INT8 NOT NULL
- ,fee_withdraw_frac INT4 NOT NULL
- ,fee_deposit_val INT8 NOT NULL
- ,fee_deposit_frac INT4 NOT NULL
- ,fee_refresh_val INT8 NOT NULL
- ,fee_refresh_frac INT4 NOT NULL
- ,fee_refund_val INT8 NOT NULL
- ,fee_refund_frac INT4 NOT NULL
+ ,coin taler_amount NOT NULL
+ ,fee_withdraw taler_amount NOT NULL
+ ,fee_deposit taler_amount NOT NULL
+ ,fee_refresh taler_amount NOT NULL
+ ,fee_refund taler_amount NOT NULL
);
COMMENT ON TABLE denominations
IS 'Main denominations table. All the valid denominations the exchange knows about.';
diff --git a/src/exchangedb/0002-deposits.sql b/src/exchangedb/0002-deposits.sql
deleted file mode 100644
index d8afdac84..000000000
--- a/src/exchangedb/0002-deposits.sql
+++ /dev/null
@@ -1,419 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2023 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-CREATE FUNCTION create_table_deposits(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(deposit_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
- ',shard INT8 NOT NULL'
- ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
- ',known_coin_id INT8 NOT NULL' -- FIXME: column needed!?
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
- ',wallet_timestamp INT8 NOT NULL'
- ',exchange_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_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)'
- ',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)'
- ',wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16)'
- ',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
- ',done BOOLEAN NOT NULL DEFAULT FALSE'
- ',policy_blocked BOOLEAN NOT NULL DEFAULT FALSE'
- ',policy_details_serial_id INT8'
- ') %s ;'
- ,table_name
- ,'PARTITION BY HASH (coin_pub)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'Deposits we have received and for which we need to make (aggregate) wire transfers (and manage refunds).'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Used for load sharding in the materialized indices. Should be set based on merchant_pub. 64-bit value because we need an *unsigned* 32-bit value.'
- ,'shard'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Used for garbage collection'
- ,'known_coin_id'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Identifies the target bank account and KYC status'
- ,'wire_target_h_payto'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Salt used when hashing the payto://-URI to get the h_wire'
- ,'wire_salt'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Set to TRUE once we have included this deposit in some aggregate wire transfer to the merchant'
- ,'done'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'True if the aggregation of the deposit is currently blocked by some policy extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.'
- ,'policy_blocked'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'References policy extensions table, NULL if extensions are not used'
- ,'policy_details_serial_id'
- ,table_name
- ,partition_suffix
- );
-END
-$$;
-
-
-CREATE FUNCTION constrain_table_deposits(
- IN partition_suffix VARCHAR
-)
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_deposit_serial_id_pkey'
- ' PRIMARY KEY (deposit_serial_id) '
- ',ADD CONSTRAINT ' || table_name || '_coin_pub_merchant_pub_h_contract_terms_key'
- ' UNIQUE (coin_pub, merchant_pub, h_contract_terms)'
- );
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_by_ready '
- 'ON ' || table_name || ' '
- '(wire_deadline ASC'
- ',shard ASC'
- ',coin_pub'
- ') WHERE NOT (done OR policy_blocked);'
- );
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_for_matching '
- 'ON ' || table_name || ' '
- '(refund_deadline ASC'
- ',merchant_pub'
- ',coin_pub'
- ') WHERE NOT (done OR policy_blocked);'
- );
-END
-$$;
-
-
-CREATE FUNCTION foreign_table_deposits()
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits';
-BEGIN
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_foreign_coin_pub'
- ' FOREIGN KEY (coin_pub) '
- ' REFERENCES known_coins (coin_pub) ON DELETE CASCADE'
- ',ADD CONSTRAINT ' || table_name || '_foreign_coin_id'
- ' FOREIGN KEY (known_coin_id) '
- ' REFERENCES known_coins (known_coin_id) ON DELETE CASCADE'
- ',ADD CONSTRAINT ' || table_name || '_foreign_policy_details'
- ' FOREIGN KEY (policy_details_serial_id) '
- ' REFERENCES policy_details (policy_details_serial_id) ON DELETE CASCADE'
- );
-END
-$$;
-
-
-CREATE FUNCTION create_table_deposits_by_ready(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits_by_ready';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(wire_deadline INT8 NOT NULL'
- ',shard INT8 NOT NULL'
- ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
- ',deposit_serial_id INT8'
- ') %s ;'
- ,table_name
- ,'PARTITION BY RANGE (wire_deadline)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'Enables fast lookups for deposits_get_ready, auto-populated via TRIGGER below'
- ,table_name
- ,partition_suffix
- );
-END
-$$;
-
-
-CREATE FUNCTION constrain_table_deposits_by_ready(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits_by_ready';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_main_index '
- 'ON ' || table_name || ' '
- '(wire_deadline ASC, shard ASC, coin_pub);'
- );
-END
-$$;
-
-
-CREATE FUNCTION create_table_deposits_for_matching(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits_for_matching';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(refund_deadline INT8 NOT NULL'
- ',merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)'
- ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)' -- REFERENCES known_coins (coin_pub) ON DELETE CASCADE
- ',deposit_serial_id INT8'
- ') %s ;'
- ,table_name
- ,'PARTITION BY RANGE (refund_deadline)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'Enables fast lookups for deposits_iterate_matching, auto-populated via TRIGGER below'
- ,table_name
- ,partition_suffix
- );
-END
-$$;
-
-
-CREATE FUNCTION constrain_table_deposits_for_matching(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'deposits_for_matching';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_main_index'
- ' ON ' || table_name || ' '
- '(refund_deadline ASC, merchant_pub, coin_pub);'
- );
-END
-$$;
-
-
-CREATE OR REPLACE FUNCTION deposits_insert_trigger()
- RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-DECLARE
- is_ready BOOLEAN;
-BEGIN
- is_ready = NOT (NEW.done OR NEW.policy_blocked);
-
- IF (is_ready)
- THEN
- INSERT INTO exchange.deposits_by_ready
- (wire_deadline
- ,shard
- ,coin_pub
- ,deposit_serial_id)
- VALUES
- (NEW.wire_deadline
- ,NEW.shard
- ,NEW.coin_pub
- ,NEW.deposit_serial_id);
- INSERT INTO exchange.deposits_for_matching
- (refund_deadline
- ,merchant_pub
- ,coin_pub
- ,deposit_serial_id)
- VALUES
- (NEW.refund_deadline
- ,NEW.merchant_pub
- ,NEW.coin_pub
- ,NEW.deposit_serial_id);
- END IF;
- RETURN NEW;
-END $$;
-COMMENT ON FUNCTION deposits_insert_trigger()
- IS 'Replicate deposit inserts into materialized indices.';
-
-
-CREATE OR REPLACE FUNCTION deposits_update_trigger()
- RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-DECLARE
- was_ready BOOLEAN;
-DECLARE
- is_ready BOOLEAN;
-BEGIN
- was_ready = NOT (OLD.done OR OLD.policy_blocked);
- is_ready = NOT (NEW.done OR NEW.policy_blocked);
- IF (was_ready AND NOT is_ready)
- THEN
- DELETE FROM exchange.deposits_by_ready
- WHERE wire_deadline = OLD.wire_deadline
- AND shard = OLD.shard
- AND coin_pub = OLD.coin_pub
- AND deposit_serial_id = OLD.deposit_serial_id;
- DELETE FROM exchange.deposits_for_matching
- WHERE refund_deadline = OLD.refund_deadline
- AND merchant_pub = OLD.merchant_pub
- AND coin_pub = OLD.coin_pub
- AND deposit_serial_id = OLD.deposit_serial_id;
- END IF;
- IF (is_ready AND NOT was_ready)
- THEN
- INSERT INTO exchange.deposits_by_ready
- (wire_deadline
- ,shard
- ,coin_pub
- ,deposit_serial_id)
- VALUES
- (NEW.wire_deadline
- ,NEW.shard
- ,NEW.coin_pub
- ,NEW.deposit_serial_id);
- INSERT INTO exchange.deposits_for_matching
- (refund_deadline
- ,merchant_pub
- ,coin_pub
- ,deposit_serial_id)
- VALUES
- (NEW.refund_deadline
- ,NEW.merchant_pub
- ,NEW.coin_pub
- ,NEW.deposit_serial_id);
- END IF;
- RETURN NEW;
-END $$;
-COMMENT ON FUNCTION deposits_update_trigger()
- IS 'Replicate deposits changes into materialized indices.';
-
-
-CREATE OR REPLACE FUNCTION deposits_delete_trigger()
- RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-DECLARE
- was_ready BOOLEAN;
-BEGIN
- was_ready = NOT (OLD.done OR OLD.policy_blocked);
-
- IF (was_ready)
- THEN
- DELETE FROM exchange.deposits_by_ready
- WHERE wire_deadline = OLD.wire_deadline
- AND shard = OLD.shard
- AND coin_pub = OLD.coin_pub
- AND deposit_serial_id = OLD.deposit_serial_id;
- DELETE FROM exchange.deposits_for_matching
- WHERE refund_deadline = OLD.refund_deadline
- AND merchant_pub = OLD.merchant_pub
- AND coin_pub = OLD.coin_pub
- AND deposit_serial_id = OLD.deposit_serial_id;
- END IF;
- RETURN NEW;
-END $$;
-COMMENT ON FUNCTION deposits_delete_trigger()
- IS 'Replicate deposit deletions into materialized indices.';
-
-
-CREATE FUNCTION master_table_deposits()
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-BEGIN
- CREATE TRIGGER deposits_on_insert
- AFTER INSERT
- ON deposits
- FOR EACH ROW EXECUTE FUNCTION deposits_insert_trigger();
- CREATE TRIGGER deposits_on_update
- AFTER UPDATE
- ON deposits
- FOR EACH ROW EXECUTE FUNCTION deposits_update_trigger();
- CREATE TRIGGER deposits_on_delete
- AFTER DELETE
- ON deposits
- FOR EACH ROW EXECUTE FUNCTION deposits_delete_trigger();
-END $$;
-
-
-INSERT INTO exchange_tables
- (name
- ,version
- ,action
- ,partitioned
- ,by_range)
- VALUES
- ('deposits'
- ,'exchange-0002'
- ,'create'
- ,TRUE
- ,FALSE),
- ('deposits'
- ,'exchange-0002'
- ,'constrain'
- ,TRUE
- ,FALSE),
- ('deposits'
- ,'exchange-0002'
- ,'foreign'
- ,TRUE
- ,FALSE)
- ;
diff --git a/src/exchangedb/0002-extensions.sql b/src/exchangedb/0002-extensions.sql
index 5642ea13a..df9e50090 100644
--- a/src/exchangedb/0002-extensions.sql
+++ b/src/exchangedb/0002-extensions.sql
@@ -16,7 +16,7 @@
CREATE TABLE extensions
(extension_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,name VARCHAR NOT NULL UNIQUE
+ ,name TEXT NOT NULL UNIQUE
,manifest BYTEA
);
COMMENT ON TABLE extensions
diff --git a/src/exchangedb/0002-global_fee.sql b/src/exchangedb/0002-global_fee.sql
index 0a2f9b495..f6526798d 100644
--- a/src/exchangedb/0002-global_fee.sql
+++ b/src/exchangedb/0002-global_fee.sql
@@ -18,12 +18,9 @@ CREATE TABLE global_fee
(global_fee_serial BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,start_date INT8 NOT NULL
,end_date INT8 NOT NULL
- ,history_fee_val INT8 NOT NULL
- ,history_fee_frac INT4 NOT NULL
- ,account_fee_val INT8 NOT NULL
- ,account_fee_frac INT4 NOT NULL
- ,purse_fee_val INT8 NOT NULL
- ,purse_fee_frac INT4 NOT NULL
+ ,history_fee taler_amount NOT NULL
+ ,account_fee taler_amount NOT NULL
+ ,purse_fee taler_amount NOT NULL
,purse_timeout INT8 NOT NULL
,history_expiration INT8 NOT NULL
,purse_account_limit INT4 NOT NULL
diff --git a/src/exchangedb/0002-history_requests.sql b/src/exchangedb/0002-history_requests.sql
index 853a435d4..0714e1bea 100644
--- a/src/exchangedb/0002-history_requests.sql
+++ b/src/exchangedb/0002-history_requests.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_history_requests(
- IN shard_suffix VARCHAR DEFAULT NULL
+ IN shard_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'history_requests';
+ table_name TEXT DEFAULT 'history_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -30,8 +30,7 @@ BEGIN
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
',request_timestamp INT8 NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
- ',history_fee_val INT8 NOT NULL'
- ',history_fee_frac INT4 NOT NULL'
+ ',history_fee taler_amount NOT NULL'
',PRIMARY KEY (reserve_pub,request_timestamp)'
') %s ;'
,table_name
@@ -57,7 +56,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'History fee approved by the signature'
- ,'history_fee_val'
+ ,'history_fee'
,table_name
,shard_suffix
);
@@ -65,13 +64,13 @@ END $$;
CREATE FUNCTION constrain_table_history_requests(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- partition_name VARCHAR;
+ partition_name TEXT;
BEGIN
partition_name = concat_ws('_', 'history_requests', partition_suffix);
@@ -89,7 +88,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'history_requests';
+ table_name TEXT DEFAULT 'history_requests';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -100,6 +99,37 @@ BEGIN
END $$;
+CREATE OR REPLACE FUNCTION history_requests_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.reserve_pub
+ ,'history_requests'
+ ,NEW.history_request_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION history_requests_insert_trigger()
+ IS 'Automatically generate reserve history entry.';
+
+
+CREATE FUNCTION master_table_history_requests()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER history_requests_on_insert
+ AFTER INSERT
+ ON history_requests
+ FOR EACH ROW EXECUTE FUNCTION history_requests_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -121,4 +151,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('history_requests'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-known_coins.sql b/src/exchangedb/0002-known_coins.sql
index 4cdb974ea..a13beff6f 100644
--- a/src/exchangedb/0002-known_coins.sql
+++ b/src/exchangedb/0002-known_coins.sql
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_known_coins(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'known_coins';
+ table_name TEXT default 'known_coins';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -31,8 +31,7 @@ BEGIN
',coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (LENGTH(coin_pub)=32)'
',age_commitment_hash BYTEA CHECK (LENGTH(age_commitment_hash)=32)'
',denom_sig BYTEA NOT NULL'
- ',remaining_val INT8 NOT NULL DEFAULT(0)'
- ',remaining_frac INT4 NOT NULL DEFAULT(0)'
+ ',remaining taler_amount NOT NULL DEFAULT(0,0)'
') %s ;'
,table_name
,'PARTITION BY HASH (coin_pub)'
@@ -57,7 +56,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Value of the coin that remains to be spent'
- ,'remaining_val'
+ ,'remaining'
,table_name
,partition_suffix
);
@@ -78,13 +77,13 @@ $$;
CREATE FUNCTION constrain_table_known_coins(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'known_coins';
+ table_name TEXT default 'known_coins';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -101,7 +100,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'known_coins';
+ table_name TEXT default 'known_coins';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0003-kyc_attributes.sql b/src/exchangedb/0002-kyc_attributes.sql
index 18093358e..66f3fc315 100644
--- a/src/exchangedb/0003-kyc_attributes.sql
+++ b/src/exchangedb/0002-kyc_attributes.sql
@@ -15,24 +15,25 @@
--
CREATE OR REPLACE FUNCTION create_table_kyc_attributes(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'kyc_attributes';
+ table_name TEXT DEFAULT 'kyc_attributes';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
'(kyc_attributes_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)'
',kyc_prox BYTEA NOT NULL CHECK (LENGTH(kyc_prox)=32)'
- ',provider VARCHAR NOT NULL'
- ',birthdate VARCHAR'
+ ',provider TEXT NOT NULL'
+ ',satisfied_checks TEXT[] NOT NULL'
',collection_time INT8 NOT NULL'
',expiration_time INT8 NOT NULL'
',encrypted_attributes BYTEA NOT NULL'
+ ',legitimization_serial INT8 NOT NULL'
') %s ;'
,table_name
,'PARTITION BY HASH (h_payto)'
@@ -56,12 +57,6 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
- 'birth date of the user, in format YYYY-MM-DD where a value of 0 is used to indicate unknown (in official documents); NULL if the birth date was not collected by the provider; used for KYC-driven age restrictions'
- ,'birthdate'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
'time when the attributes were collected by the provider'
,'collection_time'
,table_name
@@ -85,6 +80,12 @@ BEGIN
,table_name
,partition_suffix
);
+ PERFORM comment_partitioned_column(
+ 'Reference the legitimization process for which these attributes are gathered for.'
+ ,'legitimization_serial'
+ ,table_name
+ ,partition_suffix
+ );
END $$;
COMMENT ON FUNCTION create_table_kyc_attributes
@@ -92,13 +93,13 @@ COMMENT ON FUNCTION create_table_kyc_attributes
CREATE OR REPLACE FUNCTION constrain_table_kyc_attributes(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'kyc_attributes';
+ table_name TEXT DEFAULT 'kyc_attributes';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -121,6 +122,22 @@ BEGIN
END $$;
+CREATE OR REPLACE FUNCTION foreign_table_kyc_attributes()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'kyc_attributes';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_legitimization_processes'
+ ' FOREIGN KEY (legitimization_serial) '
+ ' REFERENCES legitimization_processes (legitimization_process_serial_id)' -- ON DELETE CASCADE
+ );
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -129,12 +146,17 @@ INSERT INTO exchange_tables
,by_range)
VALUES
('kyc_attributes'
- ,'exchange-0003'
+ ,'exchange-0002'
,'create'
,TRUE
,FALSE),
('kyc_attributes'
- ,'exchange-0003'
+ ,'exchange-0002'
,'constrain'
,TRUE
+ ,FALSE),
+ ('kyc_attributes'
+ ,'exchange-0002'
+ ,'foreign'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-legitimization_processes.sql b/src/exchangedb/0002-legitimization_processes.sql
index 4544a02ea..3212b1c06 100644
--- a/src/exchangedb/0002-legitimization_processes.sql
+++ b/src/exchangedb/0002-legitimization_processes.sql
@@ -15,7 +15,7 @@
--
CREATE FUNCTION create_table_legitimization_processes(
- IN shard_suffix VARCHAR DEFAULT NULL
+ IN shard_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -25,11 +25,13 @@ BEGIN
'CREATE TABLE %I'
'(legitimization_process_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)'
+ ',start_time INT8 NOT NULL'
',expiration_time INT8 NOT NULL DEFAULT (0)'
- ',provider_section VARCHAR NOT NULL'
- ',provider_user_id VARCHAR DEFAULT NULL'
- ',provider_legitimization_id VARCHAR DEFAULT NULL'
- ',UNIQUE (h_payto, provider_section)'
+ ',provider_section TEXT NOT NULL'
+ ',provider_user_id TEXT DEFAULT NULL'
+ ',provider_legitimization_id TEXT DEFAULT NULL'
+ ',redirect_url TEXT DEFAULT NULL'
+ ',finished BOOLEAN DEFAULT (FALSE)'
') %s ;'
,'legitimization_processes'
,'PARTITION BY HASH (h_payto)'
@@ -53,6 +55,18 @@ BEGIN
,shard_suffix
);
PERFORM comment_partitioned_column(
+ 'time when the KYC check was initiated, useful for garbage collection'
+ ,'expiration_time'
+ ,'legitimization_processes'
+ ,shard_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'URL where the user should go to begin the KYC process'
+ ,'redirect_url'
+ ,'legitimization_processes'
+ ,shard_suffix
+ );
+ PERFORM comment_partitioned_column(
'in the future if the respective KYC check was passed successfully'
,'expiration_time'
,'legitimization_processes'
@@ -76,19 +90,25 @@ BEGIN
,'legitimization_processes'
,shard_suffix
);
+ PERFORM comment_partitioned_column(
+ 'Set to TRUE when the specific legitimization process is finished.'
+ ,'finished'
+ ,'legitimization_processes'
+ ,shard_suffix
+ );
END
$$;
-- We need a separate function for this, as we call create_table only once but need to add
-- those constraints to each partition which gets created
CREATE FUNCTION constrain_table_legitimization_processes(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- partition_name VARCHAR;
+ partition_name TEXT;
BEGIN
partition_name = concat_ws('_', 'legitimization_processes', partition_suffix);
diff --git a/src/exchangedb/0002-legitimization_requirements.sql b/src/exchangedb/0002-legitimization_requirements.sql
index 4879b7a27..d806eb424 100644
--- a/src/exchangedb/0002-legitimization_requirements.sql
+++ b/src/exchangedb/0002-legitimization_requirements.sql
@@ -15,7 +15,7 @@
--
CREATE FUNCTION create_table_legitimization_requirements(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -25,7 +25,8 @@ BEGIN
'CREATE TABLE %I'
'(legitimization_requirement_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)'
- ',required_checks VARCHAR NOT NULL'
+ ',reserve_pub BYTEA'
+ ',required_checks TEXT NOT NULL'
',UNIQUE (h_payto, required_checks)'
') %s ;'
,'legitimization_requirements'
@@ -50,6 +51,12 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
+ 'if h_payto refers to a reserve, this is its public key, NULL otherwise. It allows to lookup the corresponding reserve when the KYC process is done.'
+ ,'reserve_pub'
+ ,'legitimization_requirements'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
'space-separated list of required checks'
,'required_checks'
,'legitimization_requirements'
@@ -61,13 +68,13 @@ $$;
-- We need a separate function for this, as we call create_table only once but need to add
-- those constraints to each partition which gets created
CREATE FUNCTION constrain_table_legitimization_requirements(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- partition_name VARCHAR;
+ partition_name TEXT;
BEGIN
partition_name = concat_ws('_', 'legitimization_requirements', partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-partner_accounts.sql b/src/exchangedb/0002-partner_accounts.sql
index 0f4af92c8..b12dc06e6 100644
--- a/src/exchangedb/0002-partner_accounts.sql
+++ b/src/exchangedb/0002-partner_accounts.sql
@@ -16,7 +16,7 @@
CREATE TABLE partner_accounts
- (payto_uri VARCHAR PRIMARY KEY
+ (payto_uri TEXT PRIMARY KEY
,partner_serial_id INT8 REFERENCES partners(partner_serial_id) ON DELETE CASCADE
,partner_master_sig BYTEA CHECK (LENGTH(partner_master_sig)=64)
,last_seen INT8 NOT NULL
diff --git a/src/exchangedb/0002-partners.sql b/src/exchangedb/0002-partners.sql
index c80f2d745..ed09378d0 100644
--- a/src/exchangedb/0002-partners.sql
+++ b/src/exchangedb/0002-partners.sql
@@ -21,8 +21,7 @@ CREATE TABLE partners
,end_date INT8 NOT NULL
,next_wad INT8 NOT NULL DEFAULT (0)
,wad_frequency INT8 NOT NULL
- ,wad_fee_val INT8 NOT NULL
- ,wad_fee_frac INT4 NOT NULL
+ ,wad_fee taler_amount NOT NULL
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
,partner_base_url TEXT NOT NULL
,PRIMARY KEY (partner_master_pub, start_date)
@@ -39,7 +38,7 @@ COMMENT ON COLUMN partners.next_wad
IS 'at what time should we do the next wad transfer to this partner (frequently updated); set to forever after the end_date';
COMMENT ON COLUMN partners.wad_frequency
IS 'how often do we promise to do wad transfers';
-COMMENT ON COLUMN partners.wad_fee_val
+COMMENT ON COLUMN partners.wad_fee
IS 'how high is the fee for a wallet to be added to a wad to this partner';
COMMENT ON COLUMN partners.partner_base_url
IS 'base URL of the REST API for this partner';
diff --git a/src/exchangedb/0002-policy_details.sql b/src/exchangedb/0002-policy_details.sql
index c9bfd1575..3acbb5c10 100644
--- a/src/exchangedb/0002-policy_details.sql
+++ b/src/exchangedb/0002-policy_details.sql
@@ -14,46 +14,162 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
--- FIXME: this table should be sharded!
-
-CREATE TABLE policy_details
- (policy_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,policy_hash_code BYTEA PRIMARY KEY CHECK(LENGTH(policy_hash_code)=16)
- ,policy_json VARCHAR
- ,deadline INT8 NOT NULL
- ,commitment_val INT8 NOT NULL
- ,commitment_frac INT4 NOT NULL
- ,accumulated_total_val INT8 NOT NULL
- ,accumulated_total_frac INT4 NOT NULL
- ,fee_val INT8 NOT NULL
- ,fee_frac INT4 NOT NULL
- ,transferable_val INT8 NOT NULL
- ,transferable_frac INT8 NOT NULL
- ,fulfillment_state smallint NOT NULL CHECK(fulfillment_state between 0 and 5)
- ,fulfillment_id BIGINT NULL REFERENCES policy_fulfillments (fulfillment_id) ON DELETE CASCADE
- );
-COMMENT ON TABLE policy_details
- IS 'Policies that were provided with deposits via policy extensions.';
-COMMENT ON COLUMN policy_details.policy_hash_code
- IS 'ID (GNUNET_HashCode) that identifies a policy. Will be calculated by the policy extension based on the content';
-COMMENT ON COLUMN policy_details.policy_json
- IS 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the policy extensions supported by the exchange.';
-COMMENT ON COLUMN policy_details.deadline
- IS 'Deadline until the policy must be marked as fulfilled (maybe "forever")';
-COMMENT ON COLUMN policy_details.commitment_val
- IS 'The amount that this policy commits to. Invariant: commitment >= fee';
-COMMENT ON COLUMN policy_details.accumulated_total_val
- IS 'The sum of all contributions of all deposit that reference this policy. Invariant: The fulfilment_state must be Insufficient as long as accumulated_total < commitment';
-COMMENT ON COLUMN policy_details.fee_val
- IS 'The fee for this policy, due when the policy is fulfilled or timed out';
-COMMENT ON COLUMN policy_details.transferable_val
- IS 'The amount that on fulfillment or timeout will be transferred to the payto-URI''s of the corresponding deposit''s. The policy fees must have been already deducted from it. Invariant: fee+transferable <= accumulated_total. The remaining amount (accumulated_total - fee - transferable) can be refreshed by the owner of the coins when the state is Timeout or Success.';
-COMMENT ON COLUMN policy_details.fulfillment_state
- IS 'State of the fulfillment:
+-- @author: Özgür Kesim
+
+CREATE FUNCTION create_table_policy_details(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'policy_details';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I '
+ '(policy_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
+ ',policy_hash_code gnunet_hashcode NOT NULL'
+ ',policy_json TEXT NOT NULL'
+ ',deadline INT8 NOT NULL'
+ ',commitment taler_amount NOT NULL'
+ ',accumulated_total taler_amount NOT NULL'
+ ',fee taler_amount NOT NULL'
+ ',transferable taler_amount NOT NULL'
+ ',fulfillment_state SMALLINT NOT NULL CHECK(fulfillment_state between 0 and 5)'
+ ',h_fulfillment_proof gnunet_hashcode'
+ ') %s;'
+ ,table_name
+ ,'PARTITION BY HASH (h_fulfillment_proof)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Policies that were provided with deposits via policy extensions.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'ID (GNUNET_HashCode) that identifies a policy. Will be calculated by the policy extension based on the content'
+ ,'policy_hash_code'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the policy extensions supported by the exchange.'
+ ,'policy_json'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Deadline until the policy must be marked as fulfilled (maybe "forever")'
+ ,'deadline'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The amount that this policy commits to. Invariant: commitment >= fee'
+ ,'commitment'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The sum of all contributions of all deposit that reference this policy. Invariant: The fulfilment_state must be Insufficient as long as accumulated_total < commitment'
+ ,'accumulated_total'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The fee for this policy, due when the policy is fulfilled or timed out'
+ ,'fee'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'The amount that on fulfillment or timeout will be transferred to the payto-URI''s of the corresponding deposit''s. The policy fees must have been already deducted from it. Invariant: fee+transferable <= accumulated_total. The remaining amount (accumulated_total - fee - transferable) can be refreshed by the owner of the coins when the state is Timeout or Success.'
+ ,'transferable'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'State of the fulfillment:
- 0 (Failure)
- 1 (Insufficient)
- 2 (Ready)
- 4 (Success)
- - 5 (Timeout)';
-COMMENT ON COLUMN policy_details.fulfillment_id
- IS 'Reference to the proof of the fulfillment of this policy, if it exists. Invariant: If not NULL, this entry''s .hash_code MUST be part of the corresponding policy_fulfillments.policy_hash_codes array.';
+ - 5 (Timeout)'
+ ,'fulfillment_state'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Reference to the proof of the fulfillment of this policy, if it exists. Invariant: If not NULL, this entry''s .hash_code MUST be part of the corresponding policy_fulfillments.policy_hash_codes array.'
+ ,'h_fulfillment_proof'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+COMMENT ON FUNCTION create_table_policy_details
+ IS 'Creates the policy_details table';
+
+
+
+
+CREATE FUNCTION constrain_table_policy_details(
+ IN partition_suffix TEXT
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ partition_name TEXT;
+BEGIN
+ partition_name = concat_ws('_', 'policy_details', partition_suffix);
+
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || partition_name ||
+ ' ADD CONSTRAINT ' || partition_name || '_unique_serial_id '
+ ' UNIQUE (policy_details_serial_id)'
+ );
+
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || partition_name ||
+ ' ADD CONSTRAINT ' || partition_name || '_unique_hash_fulfillment_proof '
+ ' UNIQUE (policy_hash_code, h_fulfillment_proof)'
+ );
+
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || partition_name || '_policy_hash_code'
+ ' ON ' || partition_name ||
+ ' (policy_hash_code);'
+ );
+END
+$$;
+
+CREATE OR REPLACE FUNCTION foreign_table_policy_details()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'policy_details';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_policy_fulfillments'
+ ' FOREIGN KEY (h_fulfillment_proof) '
+ ' REFERENCES policy_fulfillments (h_fulfillment_proof) ON DELETE RESTRICT'
+ );
+END
+$$;
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+VALUES
+ ('policy_details', 'exchange-0002', 'create', TRUE ,FALSE),
+ ('policy_details', 'exchange-0002', 'constrain', TRUE ,FALSE),
+ ('policy_details', 'exchange-0002', 'foreign', TRUE ,FALSE);
diff --git a/src/exchangedb/0002-policy_fulfillments.sql b/src/exchangedb/0002-policy_fulfillments.sql
index 54f44df52..c00947019 100644
--- a/src/exchangedb/0002-policy_fulfillments.sql
+++ b/src/exchangedb/0002-policy_fulfillments.sql
@@ -14,22 +14,88 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
--- FIXME: this table should be sharded!
+-- @author: Özgür Kesim
-CREATE TABLE policy_fulfillments
- (fulfillment_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY
- ,fulfillment_timestamp INT8 NOT NULL
- ,fulfillment_proof VARCHAR
- ,h_fulfillment_proof BYTEA NOT NULL CHECK(LENGTH(h_fulfillment_proof) = 64) UNIQUE
- ,policy_hash_codes BYTEA NOT NULL CHECK(0 = MOD(LENGTH(policy_hash_codes), 16))
+CREATE FUNCTION create_table_policy_fulfillments(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'policy_fulfillments';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I '
+ '(h_fulfillment_proof gnunet_hashcode PRIMARY KEY'
+ ',fulfillment_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
+ ',fulfillment_timestamp INT8 NOT NULL'
+ ',fulfillment_proof TEXT'
+ ',policy_hash_codes gnunet_hashcode[] NOT NULL'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (h_fulfillment_proof)'
+ ,partition_suffix
);
-COMMENT ON TABLE policy_fulfillments
- IS 'Proofs of fulfillment of policies that were set in deposits';
-COMMENT ON COLUMN policy_fulfillments.fulfillment_timestamp
- IS 'Timestamp of the arrival of a proof of fulfillment';
-COMMENT ON COLUMN policy_fulfillments.fulfillment_proof
- IS 'JSON object with a proof of the fulfillment of a policy. Supported details depend on the policy extensions supported by the exchange.';
-COMMENT ON COLUMN policy_fulfillments.h_fulfillment_proof
- IS 'Hash of the fulfillment_proof';
-COMMENT ON COLUMN policy_fulfillments.policy_hash_codes
- IS 'Concatenation of the policy_hash_code of all policy_details that are fulfilled by this proof';
+ PERFORM comment_partitioned_table(
+ 'Proofs of fulfillment of policies that were set in deposits'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Timestamp of the arrival of a proof of fulfillment'
+ ,'fulfillment_timestamp'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'JSON object with a proof of the fulfillment of a policy. Supported details depend on the policy extensions supported by the exchange.'
+ ,'fulfillment_proof'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Hash of the fulfillment_proof'
+ ,'h_fulfillment_proof'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Array of the policy_hash_code''s of all policy_details that are fulfilled by this proof'
+ ,'policy_hash_codes'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+COMMENT ON FUNCTION create_table_policy_fulfillments
+ IS 'Creates the policy_fulfillments table';
+
+CREATE FUNCTION constrain_table_policy_fulfillments(
+ IN partition_suffix TEXT
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ partition_name TEXT;
+BEGIN
+ partition_name = concat_ws('_', 'policy_fulfillments', partition_suffix);
+
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || partition_name ||
+ ' ADD CONSTRAINT ' || partition_name || '_serial_id '
+ ' UNIQUE (h_fulfillment_proof, fulfillment_id)'
+ );
+END
+$$;
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+VALUES
+ ('policy_fulfillments', 'exchange-0002', 'create', TRUE ,FALSE),
+ ('policy_fulfillments', 'exchange-0002', 'constrain', TRUE ,FALSE);
diff --git a/src/exchangedb/0002-prewire.sql b/src/exchangedb/0002-prewire.sql
index fb8dc2212..396a27608 100644
--- a/src/exchangedb/0002-prewire.sql
+++ b/src/exchangedb/0002-prewire.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,20 +15,20 @@
--
CREATE FUNCTION create_table_prewire(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'prewire';
+ table_name TEXT DEFAULT 'prewire';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
'(prewire_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY'
',wire_method TEXT NOT NULL'
- ',finished BOOLEAN NOT NULL DEFAULT false'
- ',failed BOOLEAN NOT NULL DEFAULT false'
+ ',finished BOOLEAN NOT NULL DEFAULT FALSE'
+ ',failed BOOLEAN NOT NULL DEFAULT FALSE'
',buf BYTEA NOT NULL'
') %s ;'
,table_name
@@ -63,29 +63,31 @@ $$;
CREATE FUNCTION constrain_table_prewire(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'prewire';
+ table_name TEXT DEFAULT 'prewire';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_finished_index '
'ON ' || table_name || ' '
- '(finished);'
+ '(finished)'
+ ' WHERE finished;'
);
EXECUTE FORMAT (
'COMMENT ON INDEX ' || table_name || '_by_finished_index '
- 'IS ' || quote_literal('for gc_prewire') || ';'
+ 'IS ' || quote_literal('for do_gc') || ';'
);
- -- FIXME: find a way to combine these two indices?
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_failed_finished_index '
'ON ' || table_name || ' '
- '(failed,finished);'
+ '(prewire_uuid)'
+ ' WHERE finished=FALSE'
+ ' AND failed=FALSE;'
);
EXECUTE FORMAT (
'COMMENT ON INDEX ' || table_name || '_by_failed_finished_index '
diff --git a/src/exchangedb/0002-profit_drains.sql b/src/exchangedb/0002-profit_drains.sql
index 4aba9b46e..c4f3a7bd0 100644
--- a/src/exchangedb/0002-profit_drains.sql
+++ b/src/exchangedb/0002-profit_drains.sql
@@ -17,11 +17,10 @@
CREATE TABLE profit_drains
(profit_drain_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,wtid BYTEA PRIMARY KEY CHECK (LENGTH(wtid)=32)
- ,account_section VARCHAR NOT NULL
- ,payto_uri VARCHAR NOT NULL
+ ,account_section TEXT NOT NULL
+ ,payto_uri TEXT NOT NULL
,trigger_date INT8 NOT NULL
- ,amount_val INT8 NOT NULL
- ,amount_frac INT4 NOT NULL
+ ,amount taler_amount NOT NULL
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
,executed BOOLEAN NOT NULL DEFAULT FALSE
);
@@ -35,7 +34,7 @@ COMMENT ON COLUMN profit_drains.payto_uri
IS 'specifies the account to be credited';
COMMENT ON COLUMN profit_drains.trigger_date
IS 'set by taler-exchange-offline at the time of making the signature; not necessarily the exact date of execution of the wire transfer, just for orientation';
-COMMENT ON COLUMN profit_drains.amount_val
+COMMENT ON COLUMN profit_drains.amount
IS 'amount to be transferred';
COMMENT ON COLUMN profit_drains.master_sig
IS 'EdDSA signature of type TALER_SIGNATURE_MASTER_DRAIN_PROFIT';
diff --git a/src/exchangedb/0003-purse_actions.sql b/src/exchangedb/0002-purse_actions.sql
index b4e7e132d..0dd6cfc4d 100644
--- a/src/exchangedb/0003-purse_actions.sql
+++ b/src/exchangedb/0002-purse_actions.sql
@@ -16,13 +16,13 @@
CREATE OR REPLACE FUNCTION create_table_purse_actions(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_actions';
+ table_name TEXT DEFAULT 'purse_actions';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
@@ -84,7 +84,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_actions';
+ table_name TEXT DEFAULT 'purse_actions';
BEGIN
-- Create global index
CREATE INDEX IF NOT EXISTS purse_action_by_target
@@ -110,12 +110,12 @@ INSERT INTO exchange_tables
,by_range)
VALUES
('purse_actions'
- ,'exchange-0003'
+ ,'exchange-0002'
,'create'
,TRUE
,FALSE),
('purse_actions'
- ,'exchange-0003'
+ ,'exchange-0002'
,'master'
,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-purse_decision.sql b/src/exchangedb/0002-purse_decision.sql
index e738292cd..091bd468b 100644
--- a/src/exchangedb/0002-purse_decision.sql
+++ b/src/exchangedb/0002-purse_decision.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_purse_decision(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_decision';
+ table_name TEXT DEFAULT 'purse_decision';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -51,13 +51,13 @@ END
$$;
CREATE FUNCTION constrain_table_purse_decision(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_decision';
+ table_name TEXT DEFAULT 'purse_decision';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -69,6 +69,56 @@ END
$$;
+CREATE OR REPLACE FUNCTION purse_decision_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ UPDATE purse_requests
+ SET was_decided=TRUE
+ WHERE purse_pub=NEW.purse_pub;
+ IF NEW.refunded
+ THEN
+ INSERT INTO coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ SELECT
+ pd.coin_pub
+ ,'purse_decision'
+ ,NEW.purse_decision_serial_id
+ FROM purse_deposits pd
+ WHERE purse_pub = NEW.purse_pub;
+ ELSE
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ SELECT
+ reserve_pub
+ ,'purse_decision'
+ ,NEW.purse_decision_serial_id
+ FROM purse_merges
+ WHERE purse_pub=NEW.purse_pub;
+ END IF;
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION purse_decision_insert_trigger()
+ IS 'Automatically generate coin history entry and update decision status for the purse.';
+
+
+CREATE FUNCTION master_table_purse_decision()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER purse_decision_on_insert
+ AFTER INSERT
+ ON purse_decision
+ FOR EACH ROW EXECUTE FUNCTION purse_decision_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -85,4 +135,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'constrain'
,TRUE
+ ,FALSE),
+ ('purse_decision'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-purse_deletion.sql b/src/exchangedb/0002-purse_deletion.sql
new file mode 100644
index 000000000..45b2e85a9
--- /dev/null
+++ b/src/exchangedb/0002-purse_deletion.sql
@@ -0,0 +1,110 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2022 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE OR REPLACE FUNCTION create_table_purse_deletion(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'purse_deletion';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE IF NOT EXISTS %I'
+ '(purse_deletion_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
+ ',purse_sig BYTEA CHECK (LENGTH(purse_sig)=64)'
+ ',purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32)'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (purse_pub)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'signatures affirming explicit purse deletions'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'signature of type WALLET_PURSE_DELETE'
+ ,'purse_sig'
+ ,table_name
+ ,partition_suffix
+ );
+END $$;
+
+COMMENT ON FUNCTION create_table_purse_deletion
+ IS 'Creates the purse_deletion table';
+
+
+CREATE OR REPLACE FUNCTION constrain_table_purse_deletion(
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'purse_deletion';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_delete_serial_key '
+ 'UNIQUE (purse_deletion_serial_id)'
+ );
+END $$;
+
+
+CREATE OR REPLACE FUNCTION master_table_purse_requests_was_deleted (
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'purse_requests';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE exchange.' || table_name ||
+ ' ADD COLUMN'
+ ' was_deleted BOOLEAN NOT NULL DEFAULT(FALSE)'
+ );
+ COMMENT ON COLUMN purse_requests.was_deleted
+ IS 'TRUE if the purse was explicitly deleted (purse must have an entry in the purse_deletion table)';
+END $$;
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('purse_deletion'
+ ,'exchange-0002'
+ ,'create'
+ ,TRUE
+ ,FALSE),
+ ('purse_deletion'
+ ,'exchange-0002'
+ ,'constrain'
+ ,TRUE
+ ,FALSE),
+ ('purse_requests_was_deleted'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
+ ,FALSE);
diff --git a/src/exchangedb/0002-purse_deposits.sql b/src/exchangedb/0002-purse_deposits.sql
index 9452f4344..6a07c4b62 100644
--- a/src/exchangedb/0002-purse_deposits.sql
+++ b/src/exchangedb/0002-purse_deposits.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_purse_deposits(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_deposits';
+ table_name TEXT DEFAULT 'purse_deposits';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -29,8 +29,7 @@ BEGIN
',partner_serial_id INT8'
',purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32)'
',coin_pub BYTEA NOT NULL'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
+ ',amount_with_fee taler_amount NOT NULL'
',coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)'
',PRIMARY KEY (purse_pub,coin_pub)'
') %s ;'
@@ -63,7 +62,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Total amount being deposited'
- ,'amount_with_fee_val'
+ ,'amount_with_fee'
,table_name
,partition_suffix
);
@@ -78,21 +77,16 @@ $$;
CREATE FUNCTION constrain_table_purse_deposits(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_deposits';
+ table_name TEXT DEFAULT 'purse_deposits';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by coin_pub!
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_by_coin_pub'
- ' ON ' || table_name || ' (coin_pub);'
- );
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_purse_deposit_serial_id_key'
@@ -107,7 +101,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_deposits';
+ table_name TEXT DEFAULT 'purse_deposits';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -122,6 +116,37 @@ END
$$;
+CREATE OR REPLACE FUNCTION purse_deposits_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'purse_deposits'
+ ,NEW.purse_deposit_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION purse_deposits_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_purse_deposits()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER purse_deposits_on_insert
+ AFTER INSERT
+ ON purse_deposits
+ FOR EACH ROW EXECUTE FUNCTION purse_deposits_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -143,4 +168,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('purse_deposits'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-purse_merges.sql b/src/exchangedb/0002-purse_merges.sql
index e1df57e0f..0b4d230b3 100644
--- a/src/exchangedb/0002-purse_merges.sql
+++ b/src/exchangedb/0002-purse_merges.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_purse_merges(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_merges';
+ table_name TEXT DEFAULT 'purse_merges';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -77,25 +77,16 @@ $$;
CREATE FUNCTION constrain_table_purse_merges(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_merges';
+ table_name TEXT DEFAULT 'purse_merges';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by reserve_pub!
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_reserve_pub '
- 'ON ' || table_name || ' '
- '(reserve_pub);'
- );
- EXECUTE FORMAT (
- 'COMMENT ON INDEX ' || table_name || '_reserve_pub '
- 'IS ' || quote_literal('needed in reserve history computation') || ';'
- );
+
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_purse_merge_request_serial_id_key'
@@ -110,7 +101,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_merges';
+ table_name TEXT DEFAULT 'purse_merges';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-purse_requests.sql b/src/exchangedb/0002-purse_requests.sql
index 5038c2417..0fa076338 100644
--- a/src/exchangedb/0002-purse_requests.sql
+++ b/src/exchangedb/0002-purse_requests.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_purse_requests(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_requests';
+ table_name TEXT DEFAULT 'purse_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -34,12 +34,10 @@ BEGIN
',age_limit INT4 NOT NULL'
',flags INT4 NOT NULL'
',in_reserve_quota BOOLEAN NOT NULL DEFAULT(FALSE)'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
- ',purse_fee_val INT8 NOT NULL'
- ',purse_fee_frac INT4 NOT NULL'
- ',balance_val INT8 NOT NULL DEFAULT (0)'
- ',balance_frac INT4 NOT NULL DEFAULT (0)'
+ ',was_decided BOOLEAN NOT NULL DEFAULT(FALSE)'
+ ',amount_with_fee taler_amount NOT NULL'
+ ',purse_fee taler_amount NOT NULL'
+ ',balance taler_amount NOT NULL DEFAULT (0,0)'
',purse_sig BYTEA NOT NULL CHECK(LENGTH(purse_sig)=64)'
',PRIMARY KEY (purse_pub)'
') %s ;'
@@ -90,19 +88,19 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Total amount expected to be in the purse'
- ,'amount_with_fee_val'
+ ,'amount_with_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Purse fee the client agreed to pay from the reserve (accepted by the exchange at the time the purse was created). Zero if in_reserve_quota is TRUE.'
- ,'purse_fee_val'
+ ,'purse_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Total amount actually in the purse (updated)'
- ,'balance_val'
+ ,'balance'
,table_name
,partition_suffix
);
@@ -116,28 +114,26 @@ END
$$;
CREATE FUNCTION constrain_table_purse_requests(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_requests';
+ table_name TEXT DEFAULT 'purse_requests';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by merge_pub!
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_merge_pub '
'ON ' || table_name || ' '
'(merge_pub);'
);
- -- FIXME: drop index on master (crosses partitions)?
- -- Or use materialized index? (needed?)
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_purse_expiration '
'ON ' || table_name || ' '
- '(purse_expiration);'
+ '(purse_expiration) ' ||
+ 'WHERE NOT was_decided;'
);
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-recoup.sql b/src/exchangedb/0002-recoup.sql
index 36e36d9d9..4b3452498 100644
--- a/src/exchangedb/0002-recoup.sql
+++ b/src/exchangedb/0002-recoup.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_recoup(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup';
+ table_name TEXT DEFAULT 'recoup';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -29,8 +29,7 @@ BEGIN
',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
',coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)'
',coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
+ ',amount taler_amount NOT NULL'
',recoup_timestamp INT8 NOT NULL'
',reserve_out_serial_id INT8 NOT NULL'
') %s ;'
@@ -72,13 +71,13 @@ $$;
CREATE FUNCTION constrain_table_recoup(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup';
+ table_name TEXT DEFAULT 'recoup';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -100,7 +99,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup';
+ table_name TEXT DEFAULT 'recoup';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -116,13 +115,13 @@ $$;
CREATE FUNCTION create_table_recoup_by_reserve(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup_by_reserve';
+ table_name TEXT DEFAULT 'recoup_by_reserve';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -143,13 +142,13 @@ $$;
CREATE FUNCTION constrain_table_recoup_by_reserve(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup_by_reserve';
+ table_name TEXT DEFAULT 'recoup_by_reserve';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -166,16 +165,36 @@ CREATE FUNCTION recoup_insert_trigger()
LANGUAGE plpgsql
AS $$
BEGIN
- INSERT INTO exchange.recoup_by_reserve
+ INSERT INTO recoup_by_reserve
(reserve_out_serial_id
,coin_pub)
VALUES
(NEW.reserve_out_serial_id
,NEW.coin_pub);
+ INSERT INTO coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'recoup'
+ ,NEW.recoup_uuid);
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ SELECT
+ res.reserve_pub
+ ,'recoup'
+ ,NEW.recoup_uuid
+ FROM reserves_out rout
+ JOIN reserves res
+ USING (reserve_uuid)
+ WHERE rout.reserve_out_serial_id = NEW.reserve_out_serial_id;
RETURN NEW;
END $$;
COMMENT ON FUNCTION recoup_insert_trigger()
- IS 'Replicate recoup inserts into recoup_by_reserve table.';
+ IS 'Replicates recoup inserts into recoup_by_reserve table and updates the coin_history table.';
CREATE FUNCTION recoup_delete_trigger()
@@ -183,7 +202,7 @@ CREATE FUNCTION recoup_delete_trigger()
LANGUAGE plpgsql
AS $$
BEGIN
- DELETE FROM exchange.recoup_by_reserve
+ DELETE FROM recoup_by_reserve
WHERE reserve_out_serial_id = OLD.reserve_out_serial_id
AND coin_pub = OLD.coin_pub;
RETURN OLD;
diff --git a/src/exchangedb/0002-recoup_refresh.sql b/src/exchangedb/0002-recoup_refresh.sql
index bfcfb3d8d..8b979a49f 100644
--- a/src/exchangedb/0002-recoup_refresh.sql
+++ b/src/exchangedb/0002-recoup_refresh.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_recoup_refresh(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup_refresh';
+ table_name TEXT DEFAULT 'recoup_refresh';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -31,8 +31,7 @@ BEGIN
',known_coin_id BIGINT NOT NULL'
',coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)'
',coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
+ ',amount taler_amount NOT NULL'
',recoup_timestamp INT8 NOT NULL'
',rrc_serial INT8 NOT NULL'
') %s ;'
@@ -52,7 +51,7 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
- 'FIXME: (To be) used for garbage collection (in the absence of foreign constraints, in the future)'
+ 'Used for garbage collection (in the absence of foreign constraints, in the future)'
,'known_coin_id'
,table_name
,partition_suffix
@@ -74,23 +73,27 @@ $$;
CREATE FUNCTION constrain_table_recoup_refresh(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup_refresh';
+ table_name TEXT DEFAULT 'recoup_refresh';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: any query using this index will be slow. Materialize index or change query?
- -- Also: which query uses this index?
+
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_rrc_serial_index'
' ON ' || table_name || ' '
'(rrc_serial);'
);
EXECUTE FORMAT (
+ 'COMMENT ON INDEX ' || table_name || '_by_rrc_serial_index '
+ 'IS ' || quote_literal('used in exchange_do_melt for zombie coins (rare)') || ';'
+ );
+
+ EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_coin_pub_index'
' ON ' || table_name || ' '
'(coin_pub);'
@@ -109,7 +112,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'recoup_refresh';
+ table_name TEXT DEFAULT 'recoup_refresh';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -127,6 +130,50 @@ END
$$;
+CREATE OR REPLACE FUNCTION recoup_refresh_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'recoup_refresh::NEW'
+ ,NEW.recoup_refresh_uuid);
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ SELECT
+ melt.old_coin_pub
+ ,'recoup_refresh::OLD'
+ ,NEW.recoup_refresh_uuid
+ FROM refresh_revealed_coins rrc
+ JOIN refresh_commitments melt
+ USING (melt_serial_id)
+ WHERE rrc.rrc_serial = NEW.rrc_serial;
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION coin_deposits_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_recoup_refresh()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER recoup_refresh_on_insert
+ AFTER INSERT
+ ON recoup_refresh
+ FOR EACH ROW EXECUTE FUNCTION recoup_refresh_insert_trigger();
+END $$;
+
+
+
INSERT INTO exchange_tables
(name
,version
@@ -148,4 +195,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('recoup_refresh'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-refresh_commitments.sql b/src/exchangedb/0002-refresh_commitments.sql
index 328dad5ce..e577f1e1c 100644
--- a/src/exchangedb/0002-refresh_commitments.sql
+++ b/src/exchangedb/0002-refresh_commitments.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_refresh_commitments(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_commitments';
+ table_name TEXT DEFAULT 'refresh_commitments';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -29,8 +29,7 @@ BEGIN
',rc BYTEA PRIMARY KEY CHECK (LENGTH(rc)=64)'
',old_coin_pub BYTEA NOT NULL'
',old_coin_sig BYTEA NOT NULL CHECK(LENGTH(old_coin_sig)=64)'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
+ ',amount_with_fee taler_amount NOT NULL'
',noreveal_index INT4 NOT NULL'
') %s ;'
,table_name
@@ -65,13 +64,13 @@ $$;
CREATE FUNCTION constrain_table_refresh_commitments(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_commitments';
+ table_name TEXT DEFAULT 'refresh_commitments';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
@@ -95,7 +94,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_commitments';
+ table_name TEXT DEFAULT 'refresh_commitments';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -107,6 +106,37 @@ END
$$;
+CREATE OR REPLACE FUNCTION refresh_commitments_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.old_coin_pub
+ ,'refresh_commitments'
+ ,NEW.melt_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION refresh_commitments_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_refresh_commitments()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER refresh_commitments_on_insert
+ AFTER INSERT
+ ON refresh_commitments
+ FOR EACH ROW EXECUTE FUNCTION refresh_commitments_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -128,4 +158,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('refresh_commitments'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-refresh_revealed_coins.sql b/src/exchangedb/0002-refresh_revealed_coins.sql
index 912e4bbbd..ad65c9942 100644
--- a/src/exchangedb/0002-refresh_revealed_coins.sql
+++ b/src/exchangedb/0002-refresh_revealed_coins.sql
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_refresh_revealed_coins(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_revealed_coins';
+ table_name TEXT DEFAULT 'refresh_revealed_coins';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -63,6 +63,12 @@ BEGIN
,partition_suffix
);
PERFORM comment_partitioned_column(
+ 'Signature of type WALLET_COIN_LINK, proves exchange did not tamper with the link data'
+ ,'link_sig'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
'envelope of the new coin to be signed'
,'coin_ev'
,table_name
@@ -91,13 +97,13 @@ $$;
CREATE FUNCTION constrain_table_refresh_revealed_coins(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_revealed_coins';
+ table_name TEXT DEFAULT 'refresh_revealed_coins';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -124,7 +130,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_revealed_coins';
+ table_name TEXT DEFAULT 'refresh_revealed_coins';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-refresh_transfer_keys.sql b/src/exchangedb/0002-refresh_transfer_keys.sql
index 4d10dda1b..9bcb912da 100644
--- a/src/exchangedb/0002-refresh_transfer_keys.sql
+++ b/src/exchangedb/0002-refresh_transfer_keys.sql
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_refresh_transfer_keys(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_transfer_keys';
+ table_name TEXT DEFAULT 'refresh_transfer_keys';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -68,13 +68,13 @@ $$;
CREATE FUNCTION constrain_table_refresh_transfer_keys(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_transfer_keys';
+ table_name TEXT DEFAULT 'refresh_transfer_keys';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -91,7 +91,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refresh_transfer_keys';
+ table_name TEXT DEFAULT 'refresh_transfer_keys';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-refunds.sql b/src/exchangedb/0002-refunds.sql
index 88af42db3..2a40bc192 100644
--- a/src/exchangedb/0002-refunds.sql
+++ b/src/exchangedb/0002-refunds.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,23 +15,22 @@
--
CREATE FUNCTION create_table_refunds(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refunds';
+ table_name TEXT DEFAULT 'refunds';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
'(refund_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
- ',deposit_serial_id INT8 NOT NULL'
+ ',batch_deposit_serial_id INT8 NOT NULL'
',merchant_sig BYTEA NOT NULL CHECK(LENGTH(merchant_sig)=64)'
',rtransaction_id INT8 NOT NULL'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
+ ',amount_with_fee taler_amount NOT NULL'
') %s ;'
,table_name
,'PARTITION BY HASH (coin_pub)'
@@ -44,7 +43,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Identifies ONLY the merchant_pub, h_contract_terms and coin_pub. Multiple deposits may match a refund, this only identifies one of them.'
- ,'deposit_serial_id'
+ ,'batch_deposit_serial_id'
,table_name
,partition_suffix
);
@@ -59,13 +58,13 @@ $$;
CREATE FUNCTION constrain_table_refunds (
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refunds';
+ table_name TEXT DEFAULT 'refunds';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -77,7 +76,7 @@ BEGIN
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_refund_serial_id_key'
' UNIQUE (refund_serial_id) '
- ',ADD PRIMARY KEY (deposit_serial_id, rtransaction_id) '
+ ',ADD PRIMARY KEY (batch_deposit_serial_id, rtransaction_id) '
);
END
$$;
@@ -88,7 +87,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'refunds';
+ table_name TEXT DEFAULT 'refunds';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -96,13 +95,44 @@ BEGIN
' FOREIGN KEY (coin_pub) '
' REFERENCES known_coins (coin_pub) ON DELETE CASCADE'
',ADD CONSTRAINT ' || table_name || '_foreign_deposit'
- ' FOREIGN KEY (deposit_serial_id) '
- ' REFERENCES deposits (deposit_serial_id) ON DELETE CASCADE'
+ ' FOREIGN KEY (batch_deposit_serial_id) '
+ ' REFERENCES batch_deposits (batch_deposit_serial_id) ON DELETE CASCADE'
);
END
$$;
+CREATE OR REPLACE FUNCTION refunds_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'refunds'
+ ,NEW.refund_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION refunds_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_refunds()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER refunds_on_insert
+ AFTER INSERT
+ ON refunds
+ FOR EACH ROW EXECUTE FUNCTION refunds_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -124,4 +154,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('refunds'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-reserve_history.sql b/src/exchangedb/0002-reserve_history.sql
new file mode 100644
index 000000000..b0c764306
--- /dev/null
+++ b/src/exchangedb/0002-reserve_history.sql
@@ -0,0 +1,138 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE FUNCTION create_table_reserve_history (
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'reserve_history';
+BEGIN
+ PERFORM create_partitioned_table(
+ 'CREATE TABLE %I'
+ '(reserve_history_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY'
+ ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
+ ',table_name TEXT NOT NULL'
+ ',serial_id INT8 NOT NULL'
+ ') %s ;'
+ ,table_name
+ ,'PARTITION BY HASH (reserve_pub)'
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_table(
+ 'Links to tables with entries that affected the transaction history of a reserve.'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'For which reserve is this a history entry'
+ ,'reserve_pub'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'In which table is the history entry'
+ ,'table_name'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Which is the generated serial ID of the entry in the table'
+ ,'serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+ PERFORM comment_partitioned_column(
+ 'Monotonic counter, used to generate Etags for caching'
+ ,'reserve_history_serial_id'
+ ,table_name
+ ,partition_suffix
+ );
+END
+$$;
+
+
+CREATE FUNCTION constrain_table_reserve_history(
+ IN partition_suffix TEXT
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'reserve_history';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_reserve_history_serial_id_pkey'
+ ' PRIMARY KEY (reserve_history_serial_id) '
+ ',ADD CONSTRAINT ' || table_name || '_reserve_entry_key'
+ ' UNIQUE (reserve_pub, table_name, serial_id)'
+ );
+ EXECUTE FORMAT (
+ 'CREATE INDEX ' || table_name || '_reserve_by_time'
+ ' ON ' || table_name || ' '
+ '(reserve_pub'
+ ',reserve_history_serial_id DESC'
+ ');'
+ );
+END
+$$;
+
+
+CREATE FUNCTION foreign_table_reserve_history()
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'reserve_history';
+BEGIN
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub'
+ ' FOREIGN KEY (reserve_pub) '
+ ' REFERENCES reserves (reserve_pub) ON DELETE CASCADE'
+ );
+END
+$$;
+
+
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('reserve_history'
+ ,'exchange-0002'
+ ,'create'
+ ,TRUE
+ ,FALSE),
+ ('reserve_history'
+ ,'exchange-0002'
+ ,'constrain'
+ ,TRUE
+ ,FALSE),
+ ('reserve_history'
+ ,'exchange-0002'
+ ,'foreign'
+ ,TRUE
+ ,FALSE)
+ ;
diff --git a/src/exchangedb/0002-reserves.sql b/src/exchangedb/0002-reserves.sql
index 03d17aee2..d710dd01b 100644
--- a/src/exchangedb/0002-reserves.sql
+++ b/src/exchangedb/0002-reserves.sql
@@ -15,23 +15,22 @@
--
CREATE FUNCTION create_table_reserves(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'reserves';
+ table_name TEXT DEFAULT 'reserves';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
'(reserve_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY'
',reserve_pub BYTEA PRIMARY KEY CHECK(LENGTH(reserve_pub)=32)'
- ',current_balance_val INT8 NOT NULL DEFAULT(0)'
- ',current_balance_frac INT4 NOT NULL DEFAULT(0)'
+ ',current_balance taler_amount NOT NULL DEFAULT (0, 0)'
',purses_active INT8 NOT NULL DEFAULT(0)'
',purses_allowed INT8 NOT NULL DEFAULT(0)'
- ',max_age INT4 NOT NULL DEFAULT(120)'
+ ',birthday INT4 NOT NULL DEFAULT(0)'
',expiration_date INT8 NOT NULL'
',gc_date INT8 NOT NULL'
') %s ;'
@@ -52,7 +51,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Current balance remaining with the reserve.'
- ,'current_balance_val'
+ ,'current_balance'
,table_name
,partition_suffix
);
@@ -80,18 +79,24 @@ BEGIN
,table_name
,partition_suffix
);
+ PERFORM comment_partitioned_column(
+ 'Birthday of the user in days after 1970, or 0 if user is an adult and is not subject to age restrictions'
+ ,'birthday'
+ ,table_name
+ ,partition_suffix
+ );
END
$$;
CREATE FUNCTION constrain_table_reserves(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'reserves';
+ table_name TEXT DEFAULT 'reserves';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -103,8 +108,7 @@ BEGIN
'CREATE INDEX ' || table_name || '_by_expiration_index '
'ON ' || table_name || ' '
'(expiration_date'
- ',current_balance_val'
- ',current_balance_frac'
+ ',current_balance'
');'
);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-reserves_close.sql b/src/exchangedb/0002-reserves_close.sql
index 52931b877..16669768d 100644
--- a/src/exchangedb/0002-reserves_close.sql
+++ b/src/exchangedb/0002-reserves_close.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_reserves_close(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_close';
+ table_name TEXT default 'reserves_close';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -30,10 +30,8 @@ BEGIN
',execution_date INT8 NOT NULL'
',wtid BYTEA NOT NULL CHECK (LENGTH(wtid)=32)'
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
- ',closing_fee_val INT8 NOT NULL'
- ',closing_fee_frac INT4 NOT NULL'
+ ',amount taler_amount NOT NULL'
+ ',closing_fee taler_amount NOT NULL'
',close_request_row INT8 NOT NULL DEFAULT(0)'
') %s ;'
,table_name
@@ -56,13 +54,13 @@ $$;
CREATE FUNCTION constrain_table_reserves_close(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_close';
+ table_name TEXT default 'reserves_close';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -82,7 +80,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_close';
+ table_name TEXT default 'reserves_close';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -93,6 +91,37 @@ BEGIN
END $$;
+CREATE OR REPLACE FUNCTION reserves_close_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.reserve_pub
+ ,'reserves_close'
+ ,NEW.close_uuid);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION reserves_close_insert_trigger()
+ IS 'Automatically generate reserve history entry.';
+
+
+CREATE FUNCTION master_table_reserves_close()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER reserves_close_on_insert
+ AFTER INSERT
+ ON reserves_close
+ FOR EACH ROW EXECUTE FUNCTION reserves_close_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -114,4 +143,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('reserves_close'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-reserves_in.sql b/src/exchangedb/0002-reserves_in.sql
index 410eca7c8..197a815b3 100644
--- a/src/exchangedb/0002-reserves_in.sql
+++ b/src/exchangedb/0002-reserves_in.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,21 +15,20 @@
--
CREATE FUNCTION create_table_reserves_in(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_in';
+ table_name TEXT default 'reserves_in';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
'(reserve_in_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',reserve_pub BYTEA PRIMARY KEY'
',wire_reference INT8 NOT NULL'
- ',credit_val INT8 NOT NULL'
- ',credit_frac INT4 NOT NULL'
+ ',credit taler_amount NOT NULL'
',wire_source_h_payto BYTEA CHECK (LENGTH(wire_source_h_payto)=32)'
',exchange_account_section TEXT NOT NULL'
',execution_date INT8 NOT NULL'
@@ -57,7 +56,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Amount that was transferred into the reserve'
- ,'credit_val'
+ ,'credit'
,table_name
,partition_suffix
);
@@ -65,13 +64,13 @@ END $$;
CREATE FUNCTION constrain_table_reserves_in(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_in';
+ table_name TEXT default 'reserves_in';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -84,22 +83,18 @@ BEGIN
'ON ' || table_name || ' '
'(reserve_in_serial_id);'
);
- -- FIXME: where do we need this index? Can we do better?
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_by_exch_accnt_section_execution_date_idx '
- 'ON ' || table_name || ' '
- '(exchange_account_section '
- ',execution_date'
- ');'
- );
- -- FIXME: where do we need this index? Can we do better?
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_exch_accnt_reserve_in_serial_id_idx '
'ON ' || table_name || ' '
'(exchange_account_section'
- ',reserve_in_serial_id DESC'
+ ',reserve_in_serial_id ASC'
');'
);
+ EXECUTE FORMAT (
+ 'COMMENT ON INDEX ' || table_name || '_by_exch_accnt_reserve_in_serial_id_idx '
+ 'IS ' || quote_literal ('for pg_select_reserves_in_above_serial_id_by_account') || ';'
+ );
+
END
$$;
@@ -108,7 +103,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'reserves_in';
+ table_name TEXT DEFAULT 'reserves_in';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -119,6 +114,38 @@ BEGIN
END $$;
+
+CREATE OR REPLACE FUNCTION reserves_in_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.reserve_pub
+ ,'reserves_in'
+ ,NEW.reserve_in_serial_id);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION reserves_in_insert_trigger()
+ IS 'Automatically generate reserve history entry.';
+
+
+CREATE FUNCTION master_table_reserves_in()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER reserves_in_on_insert
+ AFTER INSERT
+ ON reserves_in
+ FOR EACH ROW EXECUTE FUNCTION reserves_in_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -140,4 +167,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('reserves_in'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-reserves_open_deposits.sql b/src/exchangedb/0002-reserves_open_deposits.sql
index 35605d360..776859df8 100644
--- a/src/exchangedb/0002-reserves_open_deposits.sql
+++ b/src/exchangedb/0002-reserves_open_deposits.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_reserves_open_deposits(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_open_deposits';
+ table_name TEXT default 'reserves_open_deposits';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -30,8 +30,7 @@ BEGIN
',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)'
',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)'
- ',contribution_val INT8 NOT NULL'
- ',contribution_frac INT4 NOT NULL'
+ ',contribution taler_amount NOT NULL'
') %s ;'
,table_name
,'PARTITION BY HASH (coin_pub)'
@@ -53,13 +52,13 @@ $$;
CREATE FUNCTION constrain_table_reserves_open_deposits(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_open_deposits';
+ table_name TEXT default 'reserves_open_deposits';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -81,6 +80,37 @@ END
$$;
+CREATE OR REPLACE FUNCTION reserves_open_deposits_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO exchange.coin_history
+ (coin_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.coin_pub
+ ,'reserves_open_deposits'
+ ,NEW.reserve_open_deposit_uuid);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION reserves_open_deposits_insert_trigger()
+ IS 'Automatically generate coin history entry.';
+
+
+CREATE FUNCTION master_table_reserves_open_deposits()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER reserves_open_deposits_on_insert
+ AFTER INSERT
+ ON reserves_open_deposits
+ FOR EACH ROW EXECUTE FUNCTION reserves_open_deposits_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -97,4 +127,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'constrain'
,TRUE
+ ,FALSE),
+ ('reserves_open_deposits'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-reserves_open_requests.sql b/src/exchangedb/0002-reserves_open_requests.sql
index bbd5ec90f..b51168dc0 100644
--- a/src/exchangedb/0002-reserves_open_requests.sql
+++ b/src/exchangedb/0002-reserves_open_requests.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_reserves_open_requests(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_open_requests';
+ table_name TEXT default 'reserves_open_requests';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -30,8 +30,7 @@ BEGIN
',request_timestamp INT8 NOT NULL'
',expiration_date INT8 NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
- ',reserve_payment_val INT8 NOT NULL'
- ',reserve_payment_frac INT4 NOT NULL'
+ ',reserve_payment taler_amount NOT NULL'
',requested_purse_limit INT4 NOT NULL'
') %s ;'
,table_name
@@ -45,7 +44,7 @@ BEGIN
);
PERFORM comment_partitioned_column (
'Fee to pay for the request from the reserve balance itself.'
- ,'reserve_payment_val'
+ ,'reserve_payment'
,table_name
,partition_suffix
);
@@ -54,13 +53,13 @@ $$;
CREATE FUNCTION constrain_table_reserves_open_requests(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_open_requests';
+ table_name TEXT default 'reserves_open_requests';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -79,7 +78,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_open_requests';
+ table_name TEXT default 'reserves_open_requests';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -91,6 +90,37 @@ END
$$;
+CREATE OR REPLACE FUNCTION reserves_open_requests_insert_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ VALUES
+ (NEW.reserve_pub
+ ,'reserves_open_requests'
+ ,NEW.open_request_uuid);
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION reserves_open_requests_insert_trigger()
+ IS 'Automatically generate reserve history entry.';
+
+
+CREATE FUNCTION master_table_reserves_open_requests()
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ CREATE TRIGGER reserves_open_requests_on_insert
+ AFTER INSERT
+ ON reserves_open_requests
+ FOR EACH ROW EXECUTE FUNCTION reserves_open_requests_insert_trigger();
+END $$;
+
+
INSERT INTO exchange_tables
(name
,version
@@ -112,4 +142,9 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
+ ,FALSE),
+ ('reserves_open_requests'
+ ,'exchange-0002'
+ ,'master'
+ ,TRUE
,FALSE);
diff --git a/src/exchangedb/0002-reserves_out.sql b/src/exchangedb/0002-reserves_out.sql
index 25d717a52..f0965d222 100644
--- a/src/exchangedb/0002-reserves_out.sql
+++ b/src/exchangedb/0002-reserves_out.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_reserves_out(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_out';
+ table_name TEXT default 'reserves_out';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I'
@@ -32,8 +32,7 @@ BEGIN
',reserve_uuid INT8 NOT NULL'
',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 taler_amount NOT NULL'
') %s ;'
,'reserves_out'
,'PARTITION BY HASH (h_blind_ev)'
@@ -61,13 +60,13 @@ $$;
CREATE FUNCTION constrain_table_reserves_out(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_out';
+ table_name TEXT default 'reserves_out';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -75,7 +74,6 @@ BEGIN
' ADD CONSTRAINT ' || table_name || '_reserve_out_serial_id_key'
' UNIQUE (reserve_out_serial_id)'
);
- -- FIXME: change query to use reserves_out_by_reserve instead and materialize execution_date there as well???
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_reserve_uuid_and_execution_date_index '
'ON ' || table_name || ' '
@@ -83,7 +81,7 @@ BEGIN
);
EXECUTE FORMAT (
'COMMENT ON INDEX ' || table_name || '_by_reserve_uuid_and_execution_date_index '
- 'IS ' || quote_literal('for get_reserves_out and exchange_do_withdraw_limit_check') || ';'
+ 'IS ' || quote_literal('for do_gc, do_recoup_by_reserve, select_kyc_relevant_withdraw_events and a few others') || ';'
);
END
$$;
@@ -94,7 +92,7 @@ RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR default 'reserves_out';
+ table_name TEXT default 'reserves_out';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
@@ -109,78 +107,26 @@ END
$$;
-CREATE FUNCTION create_table_reserves_out_by_reserve(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'reserves_out_by_reserve';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(reserve_uuid INT8 NOT NULL' -- REFERENCES reserves (reserve_uuid) ON DELETE CASCADE
- ',h_blind_ev BYTEA CHECK (LENGTH(h_blind_ev)=64)'
- ') %s '
- ,table_name
- ,'PARTITION BY HASH (reserve_uuid)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table (
- 'Information in this table is strictly redundant with that of reserves_out, but saved by a different primary key for fast lookups by reserve public key/uuid.'
- ,table_name
- ,partition_suffix
- );
-END $$;
-
-
-CREATE FUNCTION constrain_table_reserves_out_by_reserve(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'reserves_out_by_reserve';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_main_index '
- 'ON ' || table_name || ' '
- '(reserve_uuid);'
- );
-END $$;
-
-
-CREATE FUNCTION reserves_out_by_reserve_insert_trigger()
+CREATE FUNCTION reserves_out_insert_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
- INSERT INTO exchange.reserves_out_by_reserve
- (reserve_uuid
- ,h_blind_ev)
- VALUES
- (NEW.reserve_uuid
- ,NEW.h_blind_ev);
+ INSERT INTO reserve_history
+ (reserve_pub
+ ,table_name
+ ,serial_id)
+ SELECT
+ res.reserve_pub
+ ,'reserves_out'
+ ,NEW.reserve_out_serial_id
+ FROM
+ reserves res
+ WHERE res.reserve_uuid = NEW.reserve_uuid;
RETURN NEW;
END $$;
-COMMENT ON FUNCTION reserves_out_by_reserve_insert_trigger()
- IS 'Replicate reserve_out inserts into reserve_out_by_reserve table.';
-
-
-CREATE FUNCTION reserves_out_by_reserve_delete_trigger()
- RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-BEGIN
- DELETE FROM exchange.reserves_out_by_reserve
- WHERE reserve_uuid = OLD.reserve_uuid;
- RETURN OLD;
-END $$;
-COMMENT ON FUNCTION reserves_out_by_reserve_delete_trigger()
- IS 'Replicate reserve_out deletions into reserve_out_by_reserve table.';
+COMMENT ON FUNCTION reserves_out_insert_trigger()
+ IS 'Replicate reserve_out inserts into reserve_history table.';
CREATE FUNCTION master_table_reserves_out()
@@ -191,14 +137,11 @@ BEGIN
CREATE TRIGGER reserves_out_on_insert
AFTER INSERT
ON reserves_out
- FOR EACH ROW EXECUTE FUNCTION reserves_out_by_reserve_insert_trigger();
- CREATE TRIGGER reserves_out_on_delete
- AFTER DELETE
- ON reserves_out
- FOR EACH ROW EXECUTE FUNCTION reserves_out_by_reserve_delete_trigger();
+ FOR EACH ROW EXECUTE FUNCTION reserves_out_insert_trigger();
END $$;
COMMENT ON FUNCTION master_table_reserves_out()
- IS 'Setup triggers to replicate reserve_out into reserve_out_by_reserve.';
+ IS 'Setup triggers to replicate reserve_out into reserve_history.';
+
INSERT INTO exchange_tables
@@ -223,16 +166,6 @@ INSERT INTO exchange_tables
,'foreign'
,TRUE
,FALSE),
- ('reserves_out_by_reserve'
- ,'exchange-0002'
- ,'create'
- ,TRUE
- ,FALSE),
- ('reserves_out_by_reserve'
- ,'exchange-0002'
- ,'constrain'
- ,TRUE
- ,FALSE),
('reserves_out'
,'exchange-0002'
,'master'
diff --git a/src/exchangedb/0002-revolving_work_shards.sql b/src/exchangedb/0002-revolving_work_shards.sql
index 83094297e..8cfff09b4 100644
--- a/src/exchangedb/0002-revolving_work_shards.sql
+++ b/src/exchangedb/0002-revolving_work_shards.sql
@@ -20,7 +20,7 @@ CREATE UNLOGGED TABLE revolving_work_shards
,start_row INT4 NOT NULL
,end_row INT4 NOT NULL
,active BOOLEAN NOT NULL DEFAULT FALSE
- ,job_name VARCHAR NOT NULL
+ ,job_name TEXT NOT NULL
,PRIMARY KEY (job_name, start_row)
);
COMMENT ON TABLE revolving_work_shards
diff --git a/src/exchangedb/0002-wad_in_entries.sql b/src/exchangedb/0002-wad_in_entries.sql
index 63c8bca2b..3ef1f1b8e 100644
--- a/src/exchangedb/0002-wad_in_entries.sql
+++ b/src/exchangedb/0002-wad_in_entries.sql
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_wad_in_entries(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_in_entries';
+ table_name TEXT DEFAULT 'wad_in_entries';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -32,12 +32,9 @@ BEGIN
',h_contract BYTEA NOT NULL CHECK(LENGTH(h_contract)=64)'
',purse_expiration INT8 NOT NULL'
',merge_timestamp INT8 NOT NULL'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
- ',wad_fee_val INT8 NOT NULL'
- ',wad_fee_frac INT4 NOT NULL'
- ',deposit_fees_val INT8 NOT NULL'
- ',deposit_fees_frac INT4 NOT NULL'
+ ',amount_with_fee taler_amount NOT NULL'
+ ',wad_fee taler_amount NOT NULL'
+ ',deposit_fees taler_amount NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
',purse_sig BYTEA NOT NULL CHECK (LENGTH(purse_sig)=64)'
') %s ;'
@@ -88,19 +85,19 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Total amount in the purse'
- ,'amount_with_fee_val'
+ ,'amount_with_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Total wad fees paid by the purse'
- ,'wad_fee_val'
+ ,'wad_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Total deposit fees paid when depositing coins into the purse'
- ,'deposit_fees_val'
+ ,'deposit_fees'
,table_name
,partition_suffix
);
@@ -120,26 +117,16 @@ END $$;
CREATE FUNCTION constrain_table_wad_in_entries(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_in_entries';
+ table_name TEXT DEFAULT 'wad_in_entries';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by reserve_pub!
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_reserve_pub '
- 'ON ' || table_name || ' '
- '(reserve_pub);'
- );
- EXECUTE FORMAT (
- 'COMMENT ON INDEX ' || table_name || '_reserve_pub '
- 'IS ' || quote_literal('needed in reserve history computation') || ';'
- );
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_wad_in_entry_serial_id_key'
@@ -153,7 +140,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_in_entries';
+ table_name TEXT DEFAULT 'wad_in_entries';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-wad_out_entries.sql b/src/exchangedb/0002-wad_out_entries.sql
index 45a4813cb..de921637b 100644
--- a/src/exchangedb/0002-wad_out_entries.sql
+++ b/src/exchangedb/0002-wad_out_entries.sql
@@ -16,13 +16,13 @@
CREATE FUNCTION create_table_wad_out_entries(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_out_entries';
+ table_name TEXT DEFAULT 'wad_out_entries';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
@@ -33,12 +33,9 @@ BEGIN
',h_contract BYTEA NOT NULL CHECK(LENGTH(h_contract)=64)'
',purse_expiration INT8 NOT NULL'
',merge_timestamp INT8 NOT NULL'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
- ',wad_fee_val INT8 NOT NULL'
- ',wad_fee_frac INT4 NOT NULL'
- ',deposit_fees_val INT8 NOT NULL'
- ',deposit_fees_frac INT4 NOT NULL'
+ ',amount_with_fee taler_amount NOT NULL'
+ ',wad_fee taler_amount NOT NULL'
+ ',deposit_fees taler_amount NOT NULL'
',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)'
',purse_sig BYTEA NOT NULL CHECK (LENGTH(purse_sig)=64)'
') %s ;'
@@ -89,19 +86,19 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Total amount in the purse'
- ,'amount_with_fee_val'
+ ,'amount_with_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Wad fee charged to the purse'
- ,'wad_fee_val'
+ ,'wad_fee'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column(
'Total deposit fees charged to the purse'
- ,'deposit_fees_val'
+ ,'deposit_fees'
,table_name
,partition_suffix
);
@@ -122,22 +119,16 @@ $$;
CREATE FUNCTION constrain_table_wad_out_entries(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_out_entries';
+ table_name TEXT DEFAULT 'wad_out_entries';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
- -- FIXME: change to materialized index by reserve_pub!
- EXECUTE FORMAT (
- 'CREATE INDEX ' || table_name || '_by_reserve_pub '
- 'ON ' || table_name || ' '
- '(reserve_pub);'
- );
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
' ADD CONSTRAINT ' || table_name || '_wad_out_entry_serial_id_key'
@@ -152,7 +143,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wad_out_entries';
+ table_name TEXT DEFAULT 'wad_out_entries';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-wads_in.sql b/src/exchangedb/0002-wads_in.sql
index 013b16350..479589ba4 100644
--- a/src/exchangedb/0002-wads_in.sql
+++ b/src/exchangedb/0002-wads_in.sql
@@ -15,21 +15,20 @@
--
CREATE FUNCTION create_table_wads_in(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wads_in';
+ table_name TEXT DEFAULT 'wads_in';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
'(wad_in_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',wad_id BYTEA PRIMARY KEY CHECK (LENGTH(wad_id)=24)'
',origin_exchange_url TEXT NOT NULL'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
+ ',amount taler_amount NOT NULL'
',arrival_time INT8 NOT NULL'
',UNIQUE (wad_id, origin_exchange_url)'
') %s ;'
@@ -56,7 +55,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Actual amount that was received by our exchange'
- ,'amount_val'
+ ,'amount'
,table_name
,partition_suffix
);
@@ -70,13 +69,13 @@ END $$;
CREATE FUNCTION constrain_table_wads_in(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wads_in';
+ table_name TEXT DEFAULT 'wads_in';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-wads_out.sql b/src/exchangedb/0002-wads_out.sql
index edad4a68d..e52010e96 100644
--- a/src/exchangedb/0002-wads_out.sql
+++ b/src/exchangedb/0002-wads_out.sql
@@ -15,21 +15,20 @@
--
CREATE FUNCTION create_table_wads_out(
- IN shard_suffix VARCHAR DEFAULT NULL
+ IN shard_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wads_out';
+ table_name TEXT DEFAULT 'wads_out';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE %I '
'(wad_out_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',wad_id BYTEA PRIMARY KEY CHECK (LENGTH(wad_id)=24)'
',partner_serial_id INT8 NOT NULL'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
+ ',amount taler_amount NOT NULL'
',execution_time INT8 NOT NULL'
') %s ;'
,table_name
@@ -55,7 +54,7 @@ BEGIN
);
PERFORM comment_partitioned_column(
'Amount that was wired'
- ,'amount_val'
+ ,'amount'
,table_name
,shard_suffix
);
@@ -70,13 +69,13 @@ $$;
CREATE FUNCTION constrain_table_wads_out(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wads_out';
+ table_name TEXT DEFAULT 'wads_out';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
@@ -93,7 +92,7 @@ RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wads_out';
+ table_name TEXT DEFAULT 'wads_out';
BEGIN
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
diff --git a/src/exchangedb/0002-wire_accounts.sql b/src/exchangedb/0002-wire_accounts.sql
index 628bc599b..dba522d7b 100644
--- a/src/exchangedb/0002-wire_accounts.sql
+++ b/src/exchangedb/0002-wire_accounts.sql
@@ -15,10 +15,13 @@
--
CREATE TABLE wire_accounts
- (payto_uri VARCHAR PRIMARY KEY
+ (payto_uri TEXT PRIMARY KEY
,master_sig BYTEA CHECK (LENGTH(master_sig)=64)
,is_active BOOLEAN NOT NULL
,last_change INT8 NOT NULL
+ ,conversion_url TEXT DEFAULT (NULL)
+ ,debit_restrictions TEXT DEFAULT (NULL)
+ ,credit_restrictions TEXT DEFAULT (NULL)
);
COMMENT ON TABLE wire_accounts
IS 'Table with current and historic bank accounts of the exchange. Entries never expire as we need to remember the last_change column indefinitely.';
@@ -30,5 +33,13 @@ COMMENT ON COLUMN wire_accounts.is_active
IS 'true if we are currently supporting the use of this account.';
COMMENT ON COLUMN wire_accounts.last_change
IS 'Latest time when active status changed. Used to detect replays of old messages.';
+COMMENT ON COLUMN wire_accounts.conversion_url
+ IS 'URL of a currency conversion service if conversion is needed when this account is used; NULL if there is no conversion.';
+COMMENT ON COLUMN wire_accounts.debit_restrictions
+ IS 'JSON array describing restrictions imposed when debiting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
+COMMENT ON COLUMN wire_accounts.credit_restrictions
+ IS 'JSON array describing restrictions imposed when crediting this account. Empty for no restrictions, NULL if account was migrated from previous database revision or account is disabled.';
+
+
-- "wire_accounts" has no sequence because it is a 'mutable' table
-- and is of no concern to the auditor
diff --git a/src/exchangedb/0002-wire_fee.sql b/src/exchangedb/0002-wire_fee.sql
index deb26ceff..12cb91b98 100644
--- a/src/exchangedb/0002-wire_fee.sql
+++ b/src/exchangedb/0002-wire_fee.sql
@@ -16,13 +16,11 @@
CREATE TABLE wire_fee
(wire_fee_serial BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,wire_method VARCHAR NOT NULL
+ ,wire_method TEXT NOT NULL
,start_date INT8 NOT NULL
,end_date INT8 NOT NULL
- ,wire_fee_val INT8 NOT NULL
- ,wire_fee_frac INT4 NOT NULL
- ,closing_fee_val INT8 NOT NULL
- ,closing_fee_frac INT4 NOT NULL
+ ,wire_fee taler_amount NOT NULL
+ ,closing_fee taler_amount NOT NULL
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
,PRIMARY KEY (wire_method, start_date)
);
diff --git a/src/exchangedb/0002-wire_out.sql b/src/exchangedb/0002-wire_out.sql
index 9c459fe95..c0f471b56 100644
--- a/src/exchangedb/0002-wire_out.sql
+++ b/src/exchangedb/0002-wire_out.sql
@@ -15,13 +15,13 @@
--
CREATE FUNCTION create_table_wire_out(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wire_out';
+ table_name TEXT DEFAULT 'wire_out';
BEGIN
PERFORM create_partitioned_table(
'CREATE TABLE IF NOT EXISTS %I'
@@ -30,9 +30,8 @@ BEGIN
',wtid_raw BYTEA UNIQUE NOT NULL CHECK (LENGTH(wtid_raw)=32)'
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
',exchange_account_section TEXT NOT NULL'
- ',amount_val INT8 NOT NULL'
- ',amount_frac INT4 NOT NULL'
- ') %s ;'
+ ',amount taler_amount NOT NULL'
+ ') %s ;'
,table_name
,'PARTITION BY HASH (wtid_raw)'
,partition_suffix
@@ -59,13 +58,13 @@ $$;
CREATE FUNCTION constrain_table_wire_out(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wire_out';
+ table_name TEXT DEFAULT 'wire_out';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-wire_targets.sql b/src/exchangedb/0002-wire_targets.sql
index 5e5421085..88d67d9a5 100644
--- a/src/exchangedb/0002-wire_targets.sql
+++ b/src/exchangedb/0002-wire_targets.sql
@@ -15,7 +15,7 @@
--
CREATE FUNCTION create_table_wire_targets(
- IN partition_suffix VARCHAR DEFAULT NULL
+ IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -25,7 +25,7 @@ BEGIN
'CREATE TABLE %I'
'(wire_target_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
',wire_target_h_payto BYTEA PRIMARY KEY CHECK (LENGTH(wire_target_h_payto)=32)'
- ',payto_uri VARCHAR NOT NULL'
+ ',payto_uri TEXT NOT NULL'
') %s ;'
,'wire_targets'
,'PARTITION BY HASH (wire_target_h_payto)'
@@ -52,13 +52,13 @@ END $$;
CREATE FUNCTION constrain_table_wire_targets(
- IN partition_suffix VARCHAR
+ IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'wire_targets';
+ table_name TEXT DEFAULT 'wire_targets';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
diff --git a/src/exchangedb/0002-work_shards.sql b/src/exchangedb/0002-work_shards.sql
index 220745d43..6347d42c5 100644
--- a/src/exchangedb/0002-work_shards.sql
+++ b/src/exchangedb/0002-work_shards.sql
@@ -20,7 +20,7 @@ CREATE TABLE work_shards
,start_row INT8 NOT NULL
,end_row INT8 NOT NULL
,completed BOOLEAN NOT NULL DEFAULT FALSE
- ,job_name VARCHAR NOT NULL
+ ,job_name TEXT NOT NULL
,PRIMARY KEY (job_name, start_row)
);
COMMENT ON TABLE work_shards
diff --git a/src/exchangedb/0003-purse_deletion.sql b/src/exchangedb/0003-purse_deletion.sql
index 69db4293c..66a95ff03 100644
--- a/src/exchangedb/0003-purse_deletion.sql
+++ b/src/exchangedb/0003-purse_deletion.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2024 Taler Systems SA
--
-- 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
@@ -14,77 +14,29 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
-CREATE OR REPLACE FUNCTION create_table_purse_deletion(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'purse_deletion';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE IF NOT EXISTS %I'
- '(purse_deletion_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
- ',purse_sig BYTEA CHECK (LENGTH(purse_sig)=64)'
- ',purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32)'
- ') %s ;'
- ,table_name
- ,'PARTITION BY HASH (purse_pub)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'signatures affirming explicit purse deletions'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'signature of type WALLET_PURSE_DELETE'
- ,'purse_sig'
- ,table_name
- ,partition_suffix
- );
-END $$;
-
-COMMENT ON FUNCTION create_table_purse_deletion
- IS 'Creates the purse_deletion table';
+-- Adds a 'unique' constraint to the 'purse_pub'.
+-- This is not only semantically correct, but also
+-- creates a dramatic speed-up on the
+-- pg_select_purse query (which otherwise fails to
+-- use indices correctly).
-
-CREATE OR REPLACE FUNCTION constrain_table_purse_deletion(
- IN partition_suffix VARCHAR DEFAULT NULL
+CREATE FUNCTION constrain_table_purse_decision3(
+ IN partition_suffix TEXT
)
-RETURNS void
+RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
- table_name VARCHAR DEFAULT 'purse_deletion';
+ table_name TEXT DEFAULT 'purse_decision';
BEGIN
table_name = concat_ws('_', table_name, partition_suffix);
EXECUTE FORMAT (
'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_delete_serial_key '
- 'UNIQUE (purse_deletion_serial_id)'
- );
-END $$;
-
-
-CREATE OR REPLACE FUNCTION master_table_purse_requests_was_deleted (
-)
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'purse_requests';
-BEGIN
- EXECUTE FORMAT (
- 'ALTER TABLE exchange.' || table_name ||
- ' ADD COLUMN'
- ' was_deleted BOOLEAN NOT NULL DEFAULT(FALSE)'
+ ' ADD CONSTRAINT ' || table_name || '_purse_decision_purse_pub'
+ ' UNIQUE (purse_pub) '
);
- COMMENT ON COLUMN purse_requests.was_deleted
- IS 'TRUE if the purse was explicitly deleted (purse must have an entry in the purse_deletion table)';
-END $$;
-
+END
+$$;
INSERT INTO exchange_tables
(name
@@ -93,18 +45,8 @@ INSERT INTO exchange_tables
,partitioned
,by_range)
VALUES
- ('purse_deletion'
- ,'exchange-0003'
- ,'create'
- ,TRUE
- ,FALSE),
- ('purse_deletion'
+ ('purse_decision3'
,'exchange-0003'
,'constrain'
,TRUE
- ,FALSE),
- ('purse_requests_was_deleted'
- ,'exchange-0003'
- ,'master'
- ,TRUE
,FALSE);
diff --git a/src/exchangedb/0003-wire_accounts.sql b/src/exchangedb/0003-wire_accounts.sql
new file mode 100644
index 000000000..51fc86c80
--- /dev/null
+++ b/src/exchangedb/0003-wire_accounts.sql
@@ -0,0 +1,25 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2024 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+-- new columns for #8000
+ALTER TABLE wire_accounts
+ ADD COLUMN priority INT8 NOT NULL DEFAULT (0),
+ ADD COLUMN bank_label TEXT DEFAULT (NULL);
+
+COMMENT ON COLUMN wire_accounts.priority
+ IS 'priority determines the order in which wallets should display wire accounts';
+COMMENT ON COLUMN wire_accounts.bank_label
+ IS 'label to show in the selector for this bank account in the wallet UI';
diff --git a/src/exchangedb/0003-withdraw_age_commitments.sql b/src/exchangedb/0003-withdraw_age_commitments.sql
deleted file mode 100644
index 6064880bd..000000000
--- a/src/exchangedb/0003-withdraw_age_commitments.sql
+++ /dev/null
@@ -1,149 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-CREATE FUNCTION create_table_withdraw_age_commitments(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_commitments';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(withdraw_age_commitment_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
- ',h_commitment BYTEA PRIMARY KEY CHECK (LENGTH(h_commitment)=64)'
- ',amount_with_fee_val INT8 NOT NULL'
- ',amount_with_fee_frac INT4 NOT NULL'
- ',max_age_group INT2 NOT NULL'
- ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)'
- ',reserve_sig BYTEA CHECK (LENGTH(reserve_sig)=64)'
- ',noreveal_index INT4 NOT NULL'
- ',timestamp INT8 NOT NULL'
- ') %s ;'
- ,table_name
- ,'PARTITION BY HASH (reserve_pub)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'Commitments made when withdrawing coins with age restriction and the gamma value chosen by the exchange.'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'The gamma value chosen by the exchange in the cut-and-choose protocol'
- ,'noreveal_index'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'The maximum age group that the client commits to with this request'
- ,'max_age_group'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Commitment made by the client, hash over the various client inputs in the cut-and-choose protocol'
- ,'h_commitment'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Reference to the public key of the reserve from which the coins are going to be withdrawn'
- ,'reserve_pub'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Signature of the reserve''s private key over the withdraw-age request'
- ,'reserve_sig'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Timestamp with the time when the withdraw-age request was received by the exchange'
- ,'timestamp'
- ,table_name
- ,partition_suffix
- );
-END
-$$;
-
-
-CREATE FUNCTION constrain_table_withdraw_age_commitments(
- IN partition_suffix VARCHAR
-)
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_commitments';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
-
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD PRIMARY KEY (h_commitment, reserve_pub);'
- );
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_withdraw_age_commitment_id_key'
- ' UNIQUE (withdraw_age_commitment_id);'
- );
-END
-$$;
-
-
-CREATE FUNCTION foreign_table_withdraw_age_commitments()
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_commitments';
-BEGIN
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_foreign_reserve_pub'
- ' FOREIGN KEY (reserve_pub)'
- ' REFERENCES reserves (reserve_pub) ON DELETE CASCADE;'
- );
-END
-$$;
-
-
-INSERT INTO exchange_tables
- (name
- ,version
- ,action
- ,partitioned
- ,by_range)
- VALUES
- ('withdraw_age_commitments'
- ,'exchange-0003'
- ,'create'
- ,TRUE
- ,FALSE),
- ('withdraw_age_commitments'
- ,'exchange-0003'
- ,'constrain'
- ,TRUE
- ,FALSE),
- ('withdraw_age_commitments'
- ,'exchange-0003'
- ,'foreign'
- ,TRUE
- ,FALSE);
diff --git a/src/exchangedb/0003-withdraw_age_reveals.sql b/src/exchangedb/0003-withdraw_age_reveals.sql
deleted file mode 100644
index 3353d9367..000000000
--- a/src/exchangedb/0003-withdraw_age_reveals.sql
+++ /dev/null
@@ -1,138 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-CREATE FUNCTION create_table_withdraw_age_reveals(
- IN partition_suffix VARCHAR DEFAULT NULL
-)
-RETURNS VOID
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_reveals';
-BEGIN
- PERFORM create_partitioned_table(
- 'CREATE TABLE %I'
- '(withdraw_age_reveals_id BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE
- ',h_commitment BYTEA NOT NULL CHECK (LENGTH(h_commitment)=32)'
- ',freshcoin_index INT4 NOT NULL'
- ',denominations_serial INT8 NOT NULL'
- ',h_coin_ev BYTEA CHECK (LENGTH(h_coin_ev)=32)'
- ') %s ;'
- ,table_name
- ,'PARTITION BY HASH (h_commitment)'
- ,partition_suffix
- );
- PERFORM comment_partitioned_table(
- 'Reveal of proofs of the correct age restriction after the commitment when withdrawing coins with age restriction'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Foreign key reference to the corresponding commitment'
- ,'h_commitment'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Index of the coin in the withdraw-age request, which is implicitly a batch request'
- ,'freshcoin_index'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Foreign key reference to the denominations'
- ,'denominations_serial'
- ,table_name
- ,partition_suffix
- );
- PERFORM comment_partitioned_column(
- 'Hash of the blinded coins'
- ,'h_coin_ev'
- ,table_name
- ,partition_suffix
- );
-END
-$$;
-
-CREATE FUNCTION constrain_table_withdraw_age_reveals(
- IN partition_suffix VARCHAR
-)
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_reveals';
-BEGIN
- table_name = concat_ws('_', table_name, partition_suffix);
-
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_withdraw_age_reveals_id_key'
- ' UNIQUE (withdraw_age_reveals_id);'
- );
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_freshcoin_index_and_h_commitment_uniqueness'
- ' UNIQUE (freshcoin_index, h_commitment);'
- );
-END
-$$;
-
-CREATE FUNCTION foreign_table_withdraw_age_reveals()
-RETURNS void
-LANGUAGE plpgsql
-AS $$
-DECLARE
- table_name VARCHAR DEFAULT 'withdraw_age_reveals';
-BEGIN
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_foreign_h_commitment'
- ' FOREIGN KEY (h_commitment)'
- ' REFERENCES withdraw_age_commitments (h_commitment) ON DELETE CASCADE;'
- );
- EXECUTE FORMAT (
- 'ALTER TABLE ' || table_name ||
- ' ADD CONSTRAINT ' || table_name || '_foreign_denominations_serial'
- ' FOREIGN KEY (denominations_serial) '
- ' REFERENCES denominations (denominations_serial) ON DELETE CASCADE;'
- );
-END
-$$;
-
-
-INSERT INTO exchange_tables
- (name
- ,version
- ,action
- ,partitioned
- ,by_range)
- VALUES
- ('withdraw_age_reveals'
- ,'exchange-0003'
- ,'create'
- ,TRUE
- ,FALSE),
- ('withdraw_age_reveals'
- ,'exchange-0003'
- ,'constrain'
- ,TRUE
- ,FALSE),
- ('withdraw_age_reveals'
- ,'exchange-0003'
- ,'foreign'
- ,TRUE
- ,FALSE);
diff --git a/src/exchangedb/0004-refunds.sql b/src/exchangedb/0004-refunds.sql
new file mode 100644
index 000000000..eb9e7ad6e
--- /dev/null
+++ b/src/exchangedb/0004-refunds.sql
@@ -0,0 +1,35 @@
+
+CREATE FUNCTION constrain_table_refunds4 (
+ IN partition_suffix TEXT DEFAULT NULL
+)
+RETURNS void
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ table_name TEXT DEFAULT 'refunds';
+BEGIN
+ table_name = concat_ws('_', table_name, partition_suffix);
+
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' DROP CONSTRAINT ' || table_name || '_pkey'
+ );
+ EXECUTE FORMAT (
+ 'ALTER TABLE ' || table_name ||
+ ' ADD PRIMARY KEY (batch_deposit_serial_id, coin_pub, rtransaction_id) '
+ );
+END
+$$;
+
+INSERT INTO exchange_tables
+ (name
+ ,version
+ ,action
+ ,partitioned
+ ,by_range)
+ VALUES
+ ('refunds4'
+ ,'exchange-0004'
+ ,'constrain'
+ ,TRUE
+ ,FALSE);
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index 71c058c13..fd993f968 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -18,16 +18,20 @@ sqlinputs = \
exchange_do_*.sql \
procedures.sql.in \
0002-*.sql \
- exchange-0002.sql.in \
0003-*.sql \
- exchange-0003.sql.in
+ 0004-*.sql \
+ exchange-0002.sql.in \
+ exchange-0003.sql.in \
+ exchange-0004.sql.in
sql_DATA = \
benchmark-0001.sql \
versioning.sql \
+ auditor-triggers-0001.sql \
exchange-0001.sql \
exchange-0002.sql \
exchange-0003.sql \
+ exchange-0004.sql \
drop.sql \
procedures.sql
@@ -39,23 +43,32 @@ BUILT_SOURCES = \
CLEANFILES = \
exchange-0002.sql \
- exchange-0003.sql
+ exchange-0003.sql \
+ procedures.sql
procedures.sql: procedures.sql.in exchange_do_*.sql
- chmod +w $@ || true
+ chmod +w $@ 2> /dev/null || true
gcc -E -P -undef - < procedures.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
exchange-0002.sql: exchange-0002.sql.in 0002-*.sql
- chmod +w $@ || true
+ chmod +w $@ 2> /dev/null || true
gcc -E -P -undef - < exchange-0002.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
exchange-0003.sql: exchange-0003.sql.in 0003-*.sql
- chmod +w $@ || true
+ chmod +w $@ 2> /dev/null || true
gcc -E -P -undef - < exchange-0003.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
chmod ugo-w $@
+exchange-0004.sql: exchange-0004.sql.in 0004-*.sql
+ chmod +w $@ 2> /dev/null || true
+ gcc -E -P -undef - < exchange-0004.sql.in 2>/dev/null | sed -e "s/--.*//" | awk 'NF' - >$@
+ chmod ugo-w $@
+
+check_SCRIPTS = \
+ test_idempotency.sh
+
EXTRA_DIST = \
exchangedb.conf \
exchangedb-postgres.conf \
@@ -63,6 +76,7 @@ EXTRA_DIST = \
test-exchange-db-postgres.conf \
$(sqlinputs) \
$(sql_DATA) \
+ $(check_SCRIPTS) \
pg_template.h pg_template.c \
pg_template.sh
@@ -79,10 +93,10 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_compute_shard.h pg_compute_shard.c \
plugin_exchangedb_postgres.c pg_helper.h \
pg_reserves_update.h pg_reserves_update.c \
- pg_insert_aggregation_tracking.h pg_insert_aggregation_tracking.c \
pg_select_aggregation_amounts_for_kyc_check.h pg_select_aggregation_amounts_for_kyc_check.c \
pg_lookup_wire_fee_by_time.h pg_lookup_wire_fee_by_time.c \
pg_select_satisfied_kyc_processes.h pg_select_satisfied_kyc_processes.c \
+ pg_get_pending_kyc_requirement_process.h pg_get_pending_kyc_requirement_process.c \
pg_kyc_provider_account_lookup.h pg_kyc_provider_account_lookup.c \
pg_lookup_kyc_requirement_by_row.h pg_lookup_kyc_requirement_by_row.c \
pg_insert_kyc_requirement_for_account.h pg_insert_kyc_requirement_for_account.c \
@@ -96,10 +110,13 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_get_drain_profit.h pg_get_drain_profit.c \
pg_get_purse_deposit.h pg_get_purse_deposit.c \
pg_insert_contract.h pg_insert_contract.c \
+ pg_select_aml_threshold.h pg_select_aml_threshold.c \
pg_select_contract.h pg_select_contract.c \
pg_select_purse_merge.h pg_select_purse_merge.c \
pg_select_contract_by_purse.h pg_select_contract_by_purse.c \
pg_insert_drain_profit.h pg_insert_drain_profit.c \
+ pg_insert_kyc_failure.h pg_insert_kyc_failure.c \
+ pg_inject_auditor_triggers.h pg_inject_auditor_triggers.c \
pg_create_tables.h pg_create_tables.c \
pg_event_listen.h pg_event_listen.c \
pg_event_listen_cancel.h pg_event_listen_cancel.c \
@@ -114,10 +131,14 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_drain_kyc_alert.h pg_drain_kyc_alert.c \
pg_reserves_in_insert.h pg_reserves_in_insert.c \
pg_get_withdraw_info.h pg_get_withdraw_info.c \
+ pg_do_age_withdraw.h pg_do_age_withdraw.c \
+ pg_get_age_withdraw.h pg_get_age_withdraw.c \
+ pg_batch_ensure_coin_known.h pg_batch_ensure_coin_known.c \
pg_do_batch_withdraw.h pg_do_batch_withdraw.c \
pg_get_policy_details.h pg_get_policy_details.c \
pg_persist_policy_details.h pg_persist_policy_details.c \
pg_do_deposit.h pg_do_deposit.c \
+ pg_get_wire_hash_for_contract.h pg_get_wire_hash_for_contract.c \
pg_add_policy_fulfillment_proof.h pg_add_policy_fulfillment_proof.c \
pg_do_melt.h pg_do_melt.c \
pg_do_refund.h pg_do_refund.c \
@@ -127,12 +148,12 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_count_known_coins.h pg_count_known_coins.c \
pg_ensure_coin_known.h pg_ensure_coin_known.c \
pg_get_known_coin.h pg_get_known_coin.c \
+ pg_get_signature_for_known_coin.h pg_get_signature_for_known_coin.c \
pg_get_coin_denomination.h pg_get_coin_denomination.c \
pg_have_deposit2.h pg_have_deposit2.c \
pg_aggregate.h pg_aggregate.c \
pg_create_aggregation_transient.h pg_create_aggregation_transient.c \
pg_insert_kyc_attributes.h pg_insert_kyc_attributes.c \
- pg_update_kyc_attributes.h pg_update_kyc_attributes.c \
pg_select_similar_kyc_attributes.h pg_select_similar_kyc_attributes.c \
pg_select_kyc_attributes.h pg_select_kyc_attributes.c \
pg_insert_aml_officer.h pg_insert_aml_officer.c \
@@ -146,7 +167,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_find_aggregation_transient.h pg_find_aggregation_transient.c \
pg_update_aggregation_transient.h pg_update_aggregation_transient.c \
pg_get_ready_deposit.h pg_get_ready_deposit.c \
- pg_insert_deposit.h pg_insert_deposit.c \
pg_insert_refund.h pg_insert_refund.c \
pg_select_refunds_by_coin.h pg_select_refunds_by_coin.c \
pg_get_melt.h pg_get_melt.c \
@@ -167,8 +187,7 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_start_deferred_wire_out.h pg_start_deferred_wire_out.c \
pg_store_wire_transfer_out.h pg_store_wire_transfer_out.c \
pg_gc.h pg_gc.c \
- pg_select_deposits_above_serial_id.h pg_select_deposits_above_serial_id.c \
- pg_select_history_requests_above_serial_id.h pg_select_history_requests_above_serial_id.c \
+ pg_select_coin_deposits_above_serial_id.h pg_select_coin_deposits_above_serial_id.c \
pg_select_purse_decisions_above_serial_id.h pg_select_purse_decisions_above_serial_id.c \
pg_select_purse_deposits_by_purse.h pg_select_purse_deposits_by_purse.c \
pg_select_refreshes_above_serial_id.h pg_select_refreshes_above_serial_id.c \
@@ -184,7 +203,9 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_get_old_coin_by_h_blind.h pg_get_old_coin_by_h_blind.c \
pg_insert_denomination_revocation.h pg_insert_denomination_revocation.c \
pg_get_denomination_revocation.h pg_get_denomination_revocation.c \
- pg_select_deposits_missing_wire.h pg_select_deposits_missing_wire.c \
+ pg_select_batch_deposits_missing_wire.h pg_select_batch_deposits_missing_wire.c \
+ pg_select_justification_for_missing_wire.h pg_select_justification_for_missing_wire.c \
+ pg_select_aggregations_above_serial.h pg_select_aggregations_above_serial.c \
pg_lookup_auditor_timestamp.h pg_lookup_auditor_timestamp.c \
pg_lookup_auditor_status.h pg_lookup_auditor_status.c \
pg_insert_auditor.h pg_insert_auditor.c \
@@ -217,7 +238,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_update_auditor.h pg_update_auditor.c \
pg_begin_revolving_shard.h pg_begin_revolving_shard.c \
pg_get_extension_manifest.h pg_get_extension_manifest.c \
- pg_insert_history_request.h pg_insert_history_request.c \
pg_do_purse_merge.h pg_do_purse_merge.c \
pg_start_read_committed.h pg_start_read_committed.c \
pg_start_read_only.h pg_start_read_only.c \
@@ -225,7 +245,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_do_batch_withdraw_insert.h pg_do_batch_withdraw_insert.c \
pg_do_reserve_open.c pg_do_reserve_open.h \
pg_do_purse_delete.c pg_do_purse_delete.h \
- pg_do_withdraw.h pg_do_withdraw.c \
pg_preflight.h pg_preflight.c \
pg_iterate_active_signkeys.h pg_iterate_active_signkeys.c \
pg_commit.h pg_commit.c \
@@ -256,18 +275,16 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_select_account_merges_above_serial_id.h pg_select_account_merges_above_serial_id.c \
pg_select_all_purse_decisions_above_serial_id.h pg_select_all_purse_decisions_above_serial_id.c \
pg_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h
-libtaler_plugin_exchangedb_postgres_la_LIBADD = \
- $(LTLIBINTL)
libtaler_plugin_exchangedb_postgres_la_LDFLAGS = \
- $(TALER_PLUGIN_LDFLAGS) \
+ $(TALER_PLUGIN_LDFLAGS)
+libtaler_plugin_exchangedb_postgres_la_LIBADD = \
+ $(LTLIBINTL) \
$(top_builddir)/src/pq/libtalerpq.la \
- $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
- -lpq \
- -lpthread \
-lgnunetpq \
-lgnunetutil \
-ljansson \
+ -lpq \
$(XLIB)
lib_LTLIBRARIES = \
@@ -300,6 +317,7 @@ noinst_PROGRAMS = \
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
TESTS = \
+ $(check_SCRIPTS) \
$(check_PROGRAMS)
test_exchangedb_postgres_SOURCES = \
diff --git a/src/exchangedb/shard-0001.sql.in b/src/exchangedb/auditor-triggers-0001.sql
index 5a849a8ae..4e2ea66ce 100644
--- a/src/exchangedb/shard-0001.sql.in
+++ b/src/exchangedb/auditor-triggers-0001.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2024 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -17,17 +17,25 @@
-- Everything in one big transaction
BEGIN;
--- Check patch versioning is in place.
-SELECT _v.register_patch('shard-0001', NULL, NULL);
+SELECT _v.register_patch('auditor-triggers-0001');
--------------------- Schema ----------------------------
+SET search_path TO exchange;
-CREATE SCHEMA exchange;
-COMMENT ON SCHEMA exchange IS 'taler-exchange data';
+CREATE OR REPLACE FUNCTION auditor_new_deposits_trigger()
+ RETURNS trigger
+ LANGUAGE plpgsql
+AS $$
+BEGIN
+ NOTIFY XFIXME;
+ RETURN NEW;
+END $$;
+COMMENT ON FUNCTION auditor_new_deposits_trigger()
+ IS 'Call XXX on new entry';
-SET search_path TO exchange;
+CREATE TRIGGER auditor_notify_helper_insert_deposits
+ AFTER INSERT
+ ON exchange.batch_deposits
+EXECUTE PROCEDURE auditor_new_deposits_trigger();
-#include "common-0001.sql"
-#include "shard-0001-part.sql"
COMMIT;
diff --git a/src/exchangedb/bench_db.c b/src/exchangedb/bench_db.c
index a85834d13..302d23062 100644
--- a/src/exchangedb/bench_db.c
+++ b/src/exchangedb/bench_db.c
@@ -169,9 +169,9 @@ bem_insert (struct GNUNET_PQ_Context *conn,
GNUNET_CRYPTO_hash (&b,
sizeof (b),
&hc);
- memcpy (&ihc,
- &hc,
- sizeof (ihc));
+ GNUNET_memcpy (&ihc,
+ &hc,
+ sizeof (ihc));
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&hc),
@@ -265,9 +265,9 @@ bem_select (struct GNUNET_PQ_Context *conn,
GNUNET_CRYPTO_hash (&b,
sizeof (b),
&hc);
- memcpy (&ihc,
- &hc,
- sizeof (ihc));
+ GNUNET_memcpy (&ihc,
+ &hc,
+ sizeof (ihc));
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint32 (&ihc),
diff --git a/src/exchangedb/drop.sql b/src/exchangedb/drop.sql
index ecebde6f5..b7583f794 100644
--- a/src/exchangedb/drop.sql
+++ b/src/exchangedb/drop.sql
@@ -17,10 +17,22 @@
-- Everything in one big transaction
BEGIN;
+WITH xpatches AS (
+ SELECT patch_name
+ FROM _v.patches
+ WHERE starts_with(patch_name,'exchange-')
+)
+ SELECT _v.unregister_patch(xpatches.patch_name)
+ FROM xpatches;
-SELECT _v.unregister_patch('exchange-0001');
-SELECT _v.unregister_patch('exchange-0002');
-SELECT _v.unregister_patch('exchange-0003');
+
+WITH xpatches AS (
+ SELECT patch_name
+ FROM _v.patches
+ WHERE starts_with(patch_name,'auditor-triggers-')
+)
+ SELECT _v.unregister_patch(xpatches.patch_name)
+ FROM xpatches;
DROP SCHEMA exchange CASCADE;
diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql
index d08aab4ea..a4b1c8b9f 100644
--- a/src/exchangedb/exchange-0001.sql
+++ b/src/exchangedb/exchange-0001.sql
@@ -29,9 +29,9 @@ SET search_path TO exchange;
CREATE TABLE exchange_tables
(table_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
- ,name VARCHAR NOT NULL
- ,version VARCHAR NOT NULL
- ,action VARCHAR NOT NULL
+ ,name TEXT NOT NULL
+ ,version TEXT NOT NULL
+ ,action TEXT NOT NULL
,partitioned BOOL NOT NULL
,by_range BOOL NOT NULL
,finished BOOL NOT NULL DEFAULT(FALSE));
@@ -52,10 +52,10 @@ COMMENT ON COLUMN exchange_tables.finished
CREATE FUNCTION create_partitioned_table(
- IN table_definition VARCHAR -- SQL template for table creation
- ,IN table_name VARCHAR -- base name of the table
- ,IN main_table_partition_str VARCHAR -- declaration for how to partition the table
- ,IN partition_suffix VARCHAR DEFAULT NULL -- NULL: no partitioning, 0: yes partitioning, no sharding, >0: sharding
+ IN table_definition TEXT -- SQL template for table creation
+ ,IN table_name TEXT -- base name of the table
+ ,IN main_table_partition_str TEXT -- declaration for how to partition the table
+ ,IN partition_suffix TEXT DEFAULT NULL -- NULL: no partitioning, 0: yes partitioning, no sharding, >0: sharding
)
RETURNS VOID
LANGUAGE plpgsql
@@ -84,9 +84,9 @@ COMMENT ON FUNCTION create_partitioned_table
CREATE FUNCTION comment_partitioned_table(
- IN table_comment VARCHAR
- ,IN table_name VARCHAR
- ,IN partition_suffix VARCHAR DEFAULT NULL
+ IN table_comment TEXT
+ ,IN table_name TEXT
+ ,IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -110,10 +110,10 @@ COMMENT ON FUNCTION comment_partitioned_table
CREATE FUNCTION comment_partitioned_column(
- IN table_comment VARCHAR
- ,IN column_name VARCHAR
- ,IN table_name VARCHAR
- ,IN partition_suffix VARCHAR DEFAULT NULL
+ IN table_comment TEXT
+ ,IN column_name TEXT
+ ,IN table_name TEXT
+ ,IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
@@ -141,7 +141,6 @@ COMMENT ON FUNCTION comment_partitioned_column
-- Main DB setup loop
---------------------------------------------------------------------------
-
CREATE FUNCTION do_create_tables(
num_partitions INTEGER
-- NULL: no partitions, add foreign constraints
diff --git a/src/exchangedb/exchange-0002.sql.in b/src/exchangedb/exchange-0002.sql.in
index 1d28f63a4..ab13b28af 100644
--- a/src/exchangedb/exchange-0002.sql.in
+++ b/src/exchangedb/exchange-0002.sql.in
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -19,6 +19,38 @@ BEGIN;
SELECT _v.register_patch('exchange-0002', NULL, NULL);
SET search_path TO exchange;
+CREATE DOMAIN gnunet_hashcode
+ AS BYTEA
+ CHECK(LENGTH(VALUE) = 32);
+
+CREATE TYPE taler_amount
+ AS
+ (val INT8
+ ,frac INT4
+ );
+COMMENT ON TYPE taler_amount
+ IS 'Stores an amount, fraction is in units of 1/100000000 of the base value';
+
+CREATE TYPE exchange_do_array_reserve_insert_return_type
+ AS
+ (transaction_duplicate BOOLEAN
+ ,ruuid INT8
+ );
+COMMENT ON TYPE exchange_do_array_reserve_insert_return_type
+ IS 'Return type for exchange_do_array_reserves_insert() stored procedure';
+
+CREATE TYPE exchange_do_select_deposits_missing_wire_return_type
+ AS
+ (
+ batch_deposit_serial_id INT8,
+ total_amount taler_amount,
+ wire_target_h_payto BYTEA,
+ deadline INT8
+ );
+COMMENT ON TYPE exchange_do_select_deposits_missing_wire_return_type
+ IS 'Return type for exchange_do_select_deposits_missing_wire';
+
+
#include "0002-denominations.sql"
#include "0002-denomination_revocations.sql"
#include "0002-wire_targets.sql"
@@ -31,10 +63,13 @@ SET search_path TO exchange;
#include "0002-exchange_sign_keys.sql"
#include "0002-signkey_revocations.sql"
#include "0002-extensions.sql"
+#include "0002-policy_fulfillments.sql"
+#include "0002-policy_details.sql"
#include "0002-profit_drains.sql"
#include "0002-legitimization_processes.sql"
#include "0002-legitimization_requirements.sql"
#include "0002-reserves.sql"
+#include "0002-reserve_history.sql"
#include "0002-reserves_in.sql"
#include "0002-reserves_close.sql"
#include "0002-close_requests.sql"
@@ -42,10 +77,12 @@ SET search_path TO exchange;
#include "0002-reserves_open_requests.sql"
#include "0002-reserves_out.sql"
#include "0002-known_coins.sql"
+#include "0002-coin_history.sql"
#include "0002-refresh_commitments.sql"
#include "0002-refresh_revealed_coins.sql"
#include "0002-refresh_transfer_keys.sql"
-#include "0002-deposits.sql"
+#include "0002-batch_deposits.sql"
+#include "0002-coin_deposits.sql"
#include "0002-refunds.sql"
#include "0002-wire_out.sql"
#include "0002-aggregation_transient.sql"
@@ -65,11 +102,17 @@ SET search_path TO exchange;
#include "0002-wad_in_entries.sql"
#include "0002-wads_out.sql"
#include "0002-wad_out_entries.sql"
-#include "0002-policy_fulfillments.sql"
-#include "0002-policy_details.sql"
#include "0002-work_shards.sql"
#include "0002-revolving_work_shards.sql"
#include "0002-partners.sql"
#include "0002-partner_accounts.sql"
+#include "0002-purse_actions.sql"
+#include "0002-purse_deletion.sql"
+#include "0002-kyc_attributes.sql"
+#include "0002-aml_status.sql"
+#include "0002-aml_staff.sql"
+#include "0002-aml_history.sql"
+#include "0002-age_withdraw.sql"
+
COMMIT;
diff --git a/src/exchangedb/exchange-0003.sql.in b/src/exchangedb/exchange-0003.sql.in
index 5461c0dd3..c94497531 100644
--- a/src/exchangedb/exchange-0003.sql.in
+++ b/src/exchangedb/exchange-0003.sql.in
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2024 Taler Systems SA
--
-- 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
@@ -19,12 +19,7 @@ BEGIN;
SELECT _v.register_patch('exchange-0003', NULL, NULL);
SET search_path TO exchange;
-#include "0003-purse_actions.sql"
+#include "0003-wire_accounts.sql"
#include "0003-purse_deletion.sql"
-#include "0003-kyc_attributes.sql"
-#include "0003-aml_status.sql"
-#include "0003-aml_staff.sql"
-#include "0003-aml_history.sql"
-
COMMIT;
diff --git a/src/exchangedb/shard-0002.sql.in b/src/exchangedb/exchange-0004.sql.in
index 552fe447f..c966aedc5 100644
--- a/src/exchangedb/shard-0002.sql.in
+++ b/src/exchangedb/exchange-0004.sql.in
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2024 Taler Systems SA
--
-- 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
@@ -14,20 +14,11 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
--- Everything in one big transaction
BEGIN;
--- Check patch versioning is in place.
-SELECT _v.register_patch('shard-0002', NULL, NULL);
-
--------------------- Schema ----------------------------
-
-CREATE SCHEMA exchange;
-COMMENT ON SCHEMA exchange IS 'taler-exchange data';
-
+SELECT _v.register_patch('exchange-0004', NULL, NULL);
SET search_path TO exchange;
-#include "common-0002.sql"
-#include "shard-0002-part.sql"
+#include "0004-refunds.sql"
COMMIT;
diff --git a/src/exchangedb/exchange_do_age_withdraw.sql b/src/exchangedb/exchange_do_age_withdraw.sql
new file mode 100644
index 000000000..89a291445
--- /dev/null
+++ b/src/exchangedb/exchange_do_age_withdraw.sql
@@ -0,0 +1,165 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+-- @author Özgür Kesim
+
+CREATE OR REPLACE FUNCTION exchange_do_age_withdraw(
+ IN amount_with_fee taler_amount,
+ IN rpub BYTEA,
+ IN rsig BYTEA,
+ IN now INT8,
+ IN min_reserve_gc INT8,
+ IN h_commitment BYTEA,
+ IN maximum_age_committed INT2, -- in years ϵ [0,1..)
+ IN noreveal_index INT2,
+ IN blinded_evs BYTEA[],
+ IN denom_serials INT8[],
+ IN denom_sigs BYTEA[],
+ OUT reserve_found BOOLEAN,
+ OUT balance_ok BOOLEAN,
+ OUT reserve_balance taler_amount,
+ OUT age_ok BOOLEAN,
+ OUT required_age INT2, -- in years ϵ [0,1..)
+ OUT reserve_birthday INT4,
+ OUT conflict BOOLEAN)
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ reserve RECORD;
+ difference RECORD;
+ balance taler_amount;
+ not_before date;
+ earliest_date date;
+BEGIN
+-- Shards: reserves by reserve_pub (SELECT)
+-- reserves_out (INSERT, with CONFLICT detection) by wih
+-- reserves by reserve_pub (UPDATE)
+-- reserves_in by reserve_pub (SELECT)
+-- wire_targets by wire_target_h_payto
+
+SELECT current_balance
+ ,birthday
+ ,gc_date
+ INTO reserve
+ FROM exchange.reserves
+ WHERE reserves.reserve_pub=rpub;
+
+IF NOT FOUND
+THEN
+ reserve_found=FALSE;
+ age_ok = FALSE;
+ required_age=-1;
+ conflict=FALSE;
+ reserve_balance.val = 0;
+ reserve_balance.frac = 0;
+ balance_ok=FALSE;
+ RETURN;
+END IF;
+
+reserve_found = TRUE;
+conflict=FALSE; -- not really yet determined
+
+reserve_balance = reserve.current_balance;
+reserve_birthday = reserve.birthday;
+
+-- Check age requirements
+IF (reserve.birthday <> 0)
+THEN
+ not_before=date '1970-01-01' + reserve.birthday;
+ earliest_date = current_date - make_interval(maximum_age_committed);
+ --
+ -- 1970-01-01 + birthday == not_before now
+ -- | | |
+ -- <.......not allowed......>[<.....allowed range......>]
+ -- | | |
+ -- ____*_____________________*_________*________________* timeline
+ -- |
+ -- earliest_date ==
+ -- now - maximum_age_committed*year
+ --
+ IF (earliest_date < not_before)
+ THEN
+ required_age = extract(year from age(current_date, not_before));
+ age_ok = FALSE;
+ balance_ok=TRUE; -- NOT REALLY
+ RETURN;
+ END IF;
+END IF;
+
+age_ok = TRUE;
+required_age=0;
+
+-- Check reserve balance is sufficient.
+SELECT *
+INTO difference
+FROM amount_left_minus_right(reserve_balance
+ ,amount_with_fee);
+
+balance_ok = difference.ok;
+
+IF NOT balance_ok
+THEN
+ RETURN;
+END IF;
+
+balance = difference.diff;
+
+-- Calculate new expiration dates.
+min_reserve_gc=GREATEST(min_reserve_gc,reserve.gc_date);
+
+-- Update reserve balance.
+UPDATE reserves SET
+ gc_date=min_reserve_gc
+ ,current_balance=balance
+WHERE
+ reserves.reserve_pub=rpub;
+
+-- Write the commitment into the age-withdraw table
+INSERT INTO exchange.age_withdraw
+ (h_commitment
+ ,max_age
+ ,amount_with_fee
+ ,reserve_pub
+ ,reserve_sig
+ ,noreveal_index
+ ,denom_serials
+ ,h_blind_evs
+ ,denom_sigs)
+VALUES
+ (h_commitment
+ ,maximum_age_committed
+ ,amount_with_fee
+ ,rpub
+ ,rsig
+ ,noreveal_index
+ ,denom_serials
+ ,blinded_evs
+ ,denom_sigs)
+ON CONFLICT DO NOTHING;
+
+IF NOT FOUND
+THEN
+ -- Signal a conflict so that the caller
+ -- can fetch the actual data from the DB.
+ conflict=TRUE;
+ RETURN;
+ELSE
+ conflict=FALSE;
+END IF;
+
+END $$;
+
+COMMENT ON FUNCTION exchange_do_age_withdraw(taler_amount, BYTEA, BYTEA, INT8, INT8, BYTEA, INT2, INT2, BYTEA[], INT8[], BYTEA[])
+ IS 'Checks whether the reserve has sufficient balance for an age-withdraw operation (or the request is repeated and was previously approved) and that age requirements are met. If so updates the database with the result. Includes storing the blinded planchets and denomination signatures, or signaling conflict';
diff --git a/src/exchangedb/exchange_do_amount_specific.sql b/src/exchangedb/exchange_do_amount_specific.sql
new file mode 100644
index 000000000..9b305a3ec
--- /dev/null
+++ b/src/exchangedb/exchange_do_amount_specific.sql
@@ -0,0 +1,92 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2022 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+--------------------------------------------------------------
+-- Taler amounts and helper functions
+-------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION amount_normalize(
+ IN amount taler_amount
+ ,OUT normalized taler_amount
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ normalized.val = amount.val + amount.frac / 100000000;
+ normalized.frac = amount.frac % 100000000;
+END $$;
+
+COMMENT ON FUNCTION amount_normalize
+ IS 'Returns the normalized amount by adding to the .val the value of (.frac / 100000000) and removing the modulus 100000000 from .frac.';
+
+CREATE OR REPLACE FUNCTION amount_add(
+ IN a taler_amount
+ ,IN b taler_amount
+ ,OUT sum taler_amount
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ sum = (a.val + b.val, a.frac + b.frac);
+ CALL amount_normalize(sum ,sum);
+
+ IF (sum.val > (1<<52))
+ THEN
+ RAISE EXCEPTION 'addition overflow';
+ END IF;
+END $$;
+
+COMMENT ON FUNCTION amount_add
+ IS 'Returns the normalized sum of two amounts. It raises an exception when the resulting .val is larger than 2^52';
+
+CREATE OR REPLACE FUNCTION amount_left_minus_right(
+ IN l taler_amount
+ ,IN r taler_amount
+ ,OUT diff taler_amount
+ ,OUT ok BOOLEAN
+)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+
+IF (l.val > r.val)
+THEN
+ ok = TRUE;
+ IF (l.frac >= r.frac)
+ THEN
+ diff.val = l.val - r.val;
+ diff.frac = l.frac - r.frac;
+ ELSE
+ diff.val = l.val - r.val - 1;
+ diff.frac = l.frac + 100000000 - r.frac;
+ END IF;
+ELSE
+ IF (l.val = r.val) AND (l.frac >= r.frac)
+ THEN
+ diff.val = 0;
+ diff.frac = l.frac - r.frac;
+ ok = TRUE;
+ ELSE
+ diff = (-1, -1);
+ ok = FALSE;
+ END IF;
+END IF;
+
+RETURN;
+END $$;
+
+COMMENT ON FUNCTION amount_left_minus_right
+ IS 'Subtracts the right amount from the left and returns the difference and TRUE, if the left amount is larger than the right, or an invalid amount and FALSE otherwise.';
diff --git a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql
deleted file mode 100644
index af9ea3195..000000000
--- a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql
+++ /dev/null
@@ -1,184 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert(
- IN in_reserve_pub BYTEA,
- IN in_expiration_date INT8,
- IN in_gc_date INT8,
- IN in_wire_ref INT8,
- IN in_credit_val INT8,
- IN in_credit_frac INT4,
- IN in_exchange_account_name VARCHAR,
- IN in_execution_date INT8,
- IN in_wire_source_h_payto BYTEA, ---h_payto
- IN in_payto_uri VARCHAR,
- IN in_reserve_expiration INT8,
- IN in_notify text,
- IN in2_notify text,
- IN in2_reserve_pub BYTEA,
- IN in2_wire_ref INT8,
- IN in2_credit_val INT8,
- IN in2_credit_frac INT4,
- IN in2_exchange_account_name VARCHAR,
- IN in2_execution_date INT8,
- IN in2_wire_source_h_payto BYTEA, ---h_payto
- IN in2_payto_uri VARCHAR,
- IN in2_reserve_expiration INT8,
- OUT out_reserve_found BOOLEAN,
- OUT out_reserve_found2 BOOLEAN,
- OUT transaction_duplicate BOOLEAN,
- OUT transaction_duplicate2 BOOLEAN,
- OUT ruuid INT8,
- OUT ruuid2 INT8)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs_reserve_exist REFCURSOR;
-DECLARE
- curs_transaction_exist refcursor;
-DECLARE
- i RECORD;
-DECLARE
- r RECORD;
-DECLARE
- k INT8;
-BEGIN
- transaction_duplicate=TRUE;
- transaction_duplicate2=TRUE;
- out_reserve_found = TRUE;
- out_reserve_found2 = TRUE;
- ruuid=0;
- ruuid2=0;
- k=0;
- INSERT INTO wire_targets
- (wire_target_h_payto
- ,payto_uri)
- VALUES
- (in_wire_source_h_payto
- ,in_payto_uri),
- (in2_wire_source_h_payto
- ,in2_payto_uri)
- ON CONFLICT DO NOTHING;
-
- OPEN curs_reserve_exist FOR
- WITH reserve_changes AS (
- INSERT INTO reserves
- (reserve_pub
- ,current_balance_val
- ,current_balance_frac
- ,expiration_date
- ,gc_date)
- VALUES
- (in_reserve_pub
- ,in_credit_val
- ,in_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in2_reserve_pub
- ,in2_credit_val
- ,in2_credit_frac
- ,in_expiration_date
- ,in_gc_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_uuid,reserve_pub)
- SELECT * FROM reserve_changes;
- WHILE k < 2 LOOP
- FETCH FROM curs_reserve_exist INTO i;
- IF FOUND
- THEN
- IF in_reserve_pub = i.reserve_pub
- THEN
- ruuid = i.reserve_uuid;
- IF in_reserve_pub <> in2_reserve_pub
- THEN
- out_reserve_found = FALSE;
- END IF;
- END IF;
- IF in2_reserve_pub = i.reserve_pub
- THEN
- out_reserve_found2 = FALSE;
- ruuid2 = i.reserve_uuid;
- END IF;
- END IF;
- k=k+1;
- END LOOP;
- CLOSE curs_reserve_exist;
-
--- FIXME: must be changed to EXECUTE FORMAT!
- PERFORM pg_notify(in_notify, NULL);
- PERFORM pg_notify(in2_notify, NULL);
-
- OPEN curs_transaction_exist FOR
- WITH reserve_in_exist AS (
- INSERT INTO reserves_in
- (reserve_pub
- ,wire_reference
- ,credit_val
- ,credit_frac
- ,exchange_account_section
- ,wire_source_h_payto
- ,execution_date)
- VALUES
- (in_reserve_pub
- ,in_wire_ref
- ,in_credit_val
- ,in_credit_frac
- ,in_exchange_account_name
- ,in_wire_source_h_payto
- ,in_execution_date),
- (in2_reserve_pub
- ,in2_wire_ref
- ,in2_credit_val
- ,in2_credit_frac
- ,in2_exchange_account_name
- ,in2_wire_source_h_payto
- ,in_execution_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_pub)
- SELECT * FROM reserve_in_exist;
- FETCH FROM curs_transaction_exist INTO r;
- IF FOUND
- THEN
- IF in_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate = FALSE;
- END IF;
- IF in2_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate2 = FALSE;
- END IF;
- FETCH FROM curs_transaction_exist INTO r;
- IF FOUND
- THEN
- IF in_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate = FALSE;
- END IF;
- IF in2_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate2 = FALSE;
- END IF;
- END IF;
- END IF;
-/* IF transaction_duplicate
- OR transaction_duplicate2
- THEN
- CLOSE curs_transaction_exist;
- ROLLBACK;
- RETURN;
- END IF;*/
- CLOSE curs_transaction_exist;
- RETURN;
-END $$;
diff --git a/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql
deleted file mode 100644
index 0d35e1214..000000000
--- a/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql
+++ /dev/null
@@ -1,285 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert(
- IN in_reserve_pub BYTEA,
- IN in_expiration_date INT8,
- IN in_gc_date INT8,
- IN in_wire_ref INT8,
- IN in_credit_val INT8,
- IN in_credit_frac INT4,
- IN in_exchange_account_name VARCHAR,
- IN in_execution_date INT8,
- IN in_wire_source_h_payto BYTEA, ---h_payto
- IN in_payto_uri VARCHAR,
- IN in_reserve_expiration INT8,
- IN in_notify text,
- IN in2_notify text,
- IN in3_notify text,
- IN in4_notify text,
- IN in2_reserve_pub BYTEA,
- IN in2_wire_ref INT8,
- IN in2_credit_val INT8,
- IN in2_credit_frac INT4,
- IN in2_exchange_account_name VARCHAR,
- IN in2_execution_date INT8,
- IN in2_wire_source_h_payto BYTEA, ---h_payto
- IN in2_payto_uri VARCHAR,
- IN in2_reserve_expiration INT8,
- IN in3_reserve_pub BYTEA,
- IN in3_wire_ref INT8,
- IN in3_credit_val INT8,
- IN in3_credit_frac INT4,
- IN in3_exchange_account_name VARCHAR,
- IN in3_execution_date INT8,
- IN in3_wire_source_h_payto BYTEA, ---h_payto
- IN in3_payto_uri VARCHAR,
- IN in3_reserve_expiration INT8,
- IN in4_reserve_pub BYTEA,
- IN in4_wire_ref INT8,
- IN in4_credit_val INT8,
- IN in4_credit_frac INT4,
- IN in4_exchange_account_name VARCHAR,
- IN in4_execution_date INT8,
- IN in4_wire_source_h_payto BYTEA, ---h_payto
- IN in4_payto_uri VARCHAR,
- IN in4_reserve_expiration INT8,
- OUT out_reserve_found BOOLEAN,
- OUT out_reserve_found2 BOOLEAN,
- OUT out_reserve_found3 BOOLEAN,
- OUT out_reserve_found4 BOOLEAN,
- OUT transaction_duplicate BOOLEAN,
- OUT transaction_duplicate2 BOOLEAN,
- OUT transaction_duplicate3 BOOLEAN,
- OUT transaction_duplicate4 BOOLEAN,
- OUT ruuid INT8,
- OUT ruuid2 INT8,
- OUT ruuid3 INT8,
- OUT ruuid4 INT8)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs_reserve_exist refcursor;
-DECLARE
- k INT8;
-DECLARE
- curs_transaction_exist refcursor;
-DECLARE
- i RECORD;
-
-BEGIN
---INITIALIZATION
- transaction_duplicate=TRUE;
- transaction_duplicate2=TRUE;
- transaction_duplicate3=TRUE;
- transaction_duplicate4=TRUE;
- out_reserve_found = TRUE;
- out_reserve_found2 = TRUE;
- out_reserve_found3 = TRUE;
- out_reserve_found4 = TRUE;
- ruuid=0;
- ruuid2=0;
- ruuid3=0;
- ruuid4=0;
- k=0;
- --SIMPLE INSERT ON CONFLICT DO NOTHING
- INSERT INTO wire_targets
- (wire_target_h_payto
- ,payto_uri)
- VALUES
- (in_wire_source_h_payto
- ,in_payto_uri),
- (in2_wire_source_h_payto
- ,in2_payto_uri),
- (in3_wire_source_h_payto
- ,in3_payto_uri),
- (in4_wire_source_h_payto
- ,in4_payto_uri)
- ON CONFLICT DO NOTHING;
-
- OPEN curs_reserve_exist FOR
- WITH reserve_changes AS (
- INSERT INTO reserves
- (reserve_pub
- ,current_balance_val
- ,current_balance_frac
- ,expiration_date
- ,gc_date)
- VALUES
- (in_reserve_pub
- ,in_credit_val
- ,in_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in2_reserve_pub
- ,in2_credit_val
- ,in2_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in3_reserve_pub
- ,in3_credit_val
- ,in3_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in4_reserve_pub
- ,in4_credit_val
- ,in4_credit_frac
- ,in_expiration_date
- ,in_gc_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_uuid,reserve_pub)
- SELECT * FROM reserve_changes;
-
- WHILE k < 4 LOOP
- FETCH FROM curs_reserve_exist INTO i;
- IF FOUND
- THEN
- IF in_reserve_pub = i.reserve_pub
- THEN
- ruuid = i.reserve_uuid;
- IF in_reserve_pub
- NOT IN (in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub)
- THEN
- out_reserve_found = FALSE;
- END IF;
- END IF;
- IF in2_reserve_pub = i.reserve_pub
- THEN
- ruuid2 = i.reserve_uuid;
- IF in2_reserve_pub
- NOT IN (in_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub)
- THEN
- out_reserve_found2 = FALSE;
- END IF;
- END IF;
- IF in3_reserve_pub = i.reserve_pub
- THEN
- ruuid3 = i.reserve_uuid;
- IF in3_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in4_reserve_pub)
- THEN
- out_reserve_found3 = FALSE;
- END IF;
- END IF;
- IF in4_reserve_pub = i.reserve_pub
- THEN
- ruuid4 = i.reserve_uuid;
- IF in4_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub)
- THEN
- out_reserve_found4 = FALSE;
- END IF;
- END IF;
- END IF;
- k=k+1;
- END LOOP;
- CLOSE curs_reserve_exist;
-
-
--- FIXME: must be changed to EXECUTE FORMAT!
- PERFORM pg_notify(in_notify, NULL);
- PERFORM pg_notify(in2_notify, NULL);
- PERFORM pg_notify(in3_notify, NULL);
- PERFORM pg_notify(in4_notify, NULL);
-
- k=0;
- OPEN curs_transaction_exist FOR
- WITH reserve_in_changes AS (
- INSERT INTO reserves_in
- (reserve_pub
- ,wire_reference
- ,credit_val
- ,credit_frac
- ,exchange_account_section
- ,wire_source_h_payto
- ,execution_date)
- VALUES
- (in_reserve_pub
- ,in_wire_ref
- ,in_credit_val
- ,in_credit_frac
- ,in_exchange_account_name
- ,in_wire_source_h_payto
- ,in_execution_date),
- (in2_reserve_pub
- ,in2_wire_ref
- ,in2_credit_val
- ,in2_credit_frac
- ,in2_exchange_account_name
- ,in2_wire_source_h_payto
- ,in_execution_date),
- (in3_reserve_pub
- ,in3_wire_ref
- ,in3_credit_val
- ,in3_credit_frac
- ,in3_exchange_account_name
- ,in3_wire_source_h_payto
- ,in_execution_date),
- (in4_reserve_pub
- ,in4_wire_ref
- ,in4_credit_val
- ,in4_credit_frac
- ,in4_exchange_account_name
- ,in4_wire_source_h_payto
- ,in_execution_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_pub)
- SELECT * FROM reserve_in_changes;
- WHILE k < 4 LOOP
- FETCH FROM curs_transaction_exist INTO i;
- IF FOUND
- THEN
- IF in_reserve_pub = i.reserve_pub
- THEN
- transaction_duplicate = FALSE;
- END IF;
- IF in2_reserve_pub = i.reserve_pub
- THEN
- transaction_duplicate2 = FALSE;
- END IF;
- IF in3_reserve_pub = i.reserve_pub
- THEN
- transaction_duplicate3 = FALSE;
- END IF;
- IF in4_reserve_pub = i.reserve_pub
- THEN
- transaction_duplicate4 = FALSE;
- END IF;
- END IF;
- k=k+1;
- END LOOP;
- /**ROLLBACK TRANSACTION IN SORTED PROCEDURE IS IT PROSSIBLE ?**/
- /*IF transaction_duplicate
- OR transaction_duplicate2
- OR transaction_duplicate3
- OR transaction_duplicate4
- THEN
- RAISE EXCEPTION 'Reserve did not exist, but INSERT into reserves_in gave conflict';
- ROLLBACK;
- CLOSE curs_transaction_exist;
- RETURN;
- END IF;*/
- CLOSE curs_transaction_exist;
- RETURN;
-
-END $$;
diff --git a/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql
deleted file mode 100644
index 8fa5ff5d5..000000000
--- a/src/exchangedb/exchange_do_batch8_reserves_in_insert.sql
+++ /dev/null
@@ -1,507 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert(
- IN in_reserve_pub BYTEA,
- IN in_expiration_date INT8,
- IN in_gc_date INT8,
- IN in_wire_ref INT8,
- IN in_credit_val INT8,
- IN in_credit_frac INT4,
- IN in_exchange_account_name VARCHAR,
- IN in_execution_date INT8,
- IN in_wire_source_h_payto BYTEA, ---h_payto
- IN in_payto_uri VARCHAR,
- IN in_reserve_expiration INT8,
- IN in_notify text,
- IN in2_notify text,
- IN in3_notify text,
- IN in4_notify text,
- IN in5_notify text,
- IN in6_notify text,
- IN in7_notify text,
- IN in8_notify text,
- IN in2_reserve_pub BYTEA,
- IN in2_wire_ref INT8,
- IN in2_credit_val INT8,
- IN in2_credit_frac INT4,
- IN in2_exchange_account_name VARCHAR,
- IN in2_execution_date INT8,
- IN in2_wire_source_h_payto BYTEA, ---h_payto
- IN in2_payto_uri VARCHAR,
- IN in2_reserve_expiration INT8,
- IN in3_reserve_pub BYTEA,
- IN in3_wire_ref INT8,
- IN in3_credit_val INT8,
- IN in3_credit_frac INT4,
- IN in3_exchange_account_name VARCHAR,
- IN in3_execution_date INT8,
- IN in3_wire_source_h_payto BYTEA, ---h_payto
- IN in3_payto_uri VARCHAR,
- IN in3_reserve_expiration INT8,
- IN in4_reserve_pub BYTEA,
- IN in4_wire_ref INT8,
- IN in4_credit_val INT8,
- IN in4_credit_frac INT4,
- IN in4_exchange_account_name VARCHAR,
- IN in4_execution_date INT8,
- IN in4_wire_source_h_payto BYTEA, ---h_payto
- IN in4_payto_uri VARCHAR,
- IN in4_reserve_expiration INT8,
- IN in5_reserve_pub BYTEA,
- IN in5_wire_ref INT8,
- IN in5_credit_val INT8,
- IN in5_credit_frac INT4,
- IN in5_exchange_account_name VARCHAR,
- IN in5_execution_date INT8,
- IN in5_wire_source_h_payto BYTEA, ---h_payto
- IN in5_payto_uri VARCHAR,
- IN in5_reserve_expiration INT8,
- IN in6_reserve_pub BYTEA,
- IN in6_wire_ref INT8,
- IN in6_credit_val INT8,
- IN in6_credit_frac INT4,
- IN in6_exchange_account_name VARCHAR,
- IN in6_execution_date INT8,
- IN in6_wire_source_h_payto BYTEA, ---h_payto
- IN in6_payto_uri VARCHAR,
- IN in6_reserve_expiration INT8,
- IN in7_reserve_pub BYTEA,
- IN in7_wire_ref INT8,
- IN in7_credit_val INT8,
- IN in7_credit_frac INT4,
- IN in7_exchange_account_name VARCHAR,
- IN in7_execution_date INT8,
- IN in7_wire_source_h_payto BYTEA, ---h_payto
- IN in7_payto_uri VARCHAR,
- IN in7_reserve_expiration INT8,
- IN in8_reserve_pub BYTEA,
- IN in8_wire_ref INT8,
- IN in8_credit_val INT8,
- IN in8_credit_frac INT4,
- IN in8_exchange_account_name VARCHAR,
- IN in8_execution_date INT8,
- IN in8_wire_source_h_payto BYTEA, ---h_payto
- IN in8_payto_uri VARCHAR,
- IN in8_reserve_expiration INT8,
- OUT out_reserve_found BOOLEAN,
- OUT out_reserve_found2 BOOLEAN,
- OUT out_reserve_found3 BOOLEAN,
- OUT out_reserve_found4 BOOLEAN,
- OUT out_reserve_found5 BOOLEAN,
- OUT out_reserve_found6 BOOLEAN,
- OUT out_reserve_found7 BOOLEAN,
- OUT out_reserve_found8 BOOLEAN,
- OUT transaction_duplicate BOOLEAN,
- OUT transaction_duplicate2 BOOLEAN,
- OUT transaction_duplicate3 BOOLEAN,
- OUT transaction_duplicate4 BOOLEAN,
- OUT transaction_duplicate5 BOOLEAN,
- OUT transaction_duplicate6 BOOLEAN,
- OUT transaction_duplicate7 BOOLEAN,
- OUT transaction_duplicate8 BOOLEAN,
- OUT ruuid INT8,
- OUT ruuid2 INT8,
- OUT ruuid3 INT8,
- OUT ruuid4 INT8,
- OUT ruuid5 INT8,
- OUT ruuid6 INT8,
- OUT ruuid7 INT8,
- OUT ruuid8 INT8)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs_reserve_existed refcursor;
-DECLARE
- k INT8;
-DECLARE
- curs_transaction_existed refcursor;
-
-DECLARE
- i RECORD;
-DECLARE
- r RECORD;
-
-BEGIN
---INITIALIZATION
- transaction_duplicate=TRUE;
- transaction_duplicate2=TRUE;
- transaction_duplicate3=TRUE;
- transaction_duplicate4=TRUE;
- transaction_duplicate5=TRUE;
- transaction_duplicate6=TRUE;
- transaction_duplicate7=TRUE;
- transaction_duplicate8=TRUE;
- out_reserve_found = TRUE;
- out_reserve_found2 = TRUE;
- out_reserve_found3 = TRUE;
- out_reserve_found4 = TRUE;
- out_reserve_found5 = TRUE;
- out_reserve_found6 = TRUE;
- out_reserve_found7 = TRUE;
- out_reserve_found8 = TRUE;
- ruuid=0;
- ruuid2=0;
- ruuid3=0;
- ruuid4=0;
- ruuid5=0;
- ruuid6=0;
- ruuid7=0;
- ruuid8=0;
- k=0;
-
- --SIMPLE INSERT ON CONFLICT DO NOTHING
- INSERT INTO wire_targets
- (wire_target_h_payto
- ,payto_uri)
- VALUES
- (in_wire_source_h_payto
- ,in_payto_uri),
- (in2_wire_source_h_payto
- ,in2_payto_uri),
- (in3_wire_source_h_payto
- ,in3_payto_uri),
- (in4_wire_source_h_payto
- ,in4_payto_uri),
- (in5_wire_source_h_payto
- ,in5_payto_uri),
- (in6_wire_source_h_payto
- ,in6_payto_uri),
- (in7_wire_source_h_payto
- ,in7_payto_uri),
- (in8_wire_source_h_payto
- ,in8_payto_uri)
- ON CONFLICT DO NOTHING;
-
- OPEN curs_reserve_existed FOR
- WITH reserve_changes AS (
- INSERT INTO reserves
- (reserve_pub
- ,current_balance_val
- ,current_balance_frac
- ,expiration_date
- ,gc_date)
- VALUES
- (in_reserve_pub
- ,in_credit_val
- ,in_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in2_reserve_pub
- ,in2_credit_val
- ,in2_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in3_reserve_pub
- ,in3_credit_val
- ,in3_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in4_reserve_pub
- ,in4_credit_val
- ,in4_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in5_reserve_pub
- ,in5_credit_val
- ,in5_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in6_reserve_pub
- ,in6_credit_val
- ,in6_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in7_reserve_pub
- ,in7_credit_val
- ,in7_credit_frac
- ,in_expiration_date
- ,in_gc_date),
- (in8_reserve_pub
- ,in8_credit_val
- ,in8_credit_frac
- ,in_expiration_date
- ,in_gc_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_uuid,reserve_pub)
- SELECT * FROM reserve_changes;
-
- WHILE k < 8 LOOP
-
- FETCH FROM curs_reserve_existed INTO i;
- IF FOUND
- THEN
- IF in_reserve_pub = i.reserve_pub
- THEN
- ruuid = i.reserve_uuid;
- IF in_reserve_pub
- NOT IN (in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found = FALSE;
- END IF;
- END IF;
- IF in2_reserve_pub = i.reserve_pub
- THEN
- ruuid2 = i.reserve_uuid;
- IF in2_reserve_pub
- NOT IN (in_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found2 = FALSE;
- END IF;
- END IF;
- IF in3_reserve_pub = i.reserve_pub
- THEN
- ruuid3 = i.reserve_uuid;
- IF in3_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found3 = FALSE;
- END IF;
- END IF;
- IF in4_reserve_pub = i.reserve_pub
- THEN
- ruuid4 = i.reserve_uuid;
- IF in4_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found4 = FALSE;
- END IF;
- END IF;
- IF in5_reserve_pub = i.reserve_pub
- THEN
- ruuid5 = i.reserve_uuid;
- IF in5_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found5 = FALSE;
- END IF;
- END IF;
- IF in6_reserve_pub = i.reserve_pub
- THEN
- ruuid6 = i.reserve_uuid;
- IF in6_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in7_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found6 = FALSE;
- END IF;
- END IF;
- IF in7_reserve_pub = i.reserve_pub
- THEN
- ruuid7 = i.reserve_uuid;
- IF in7_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in8_reserve_pub)
- THEN
- out_reserve_found7 = FALSE;
- END IF;
- END IF;
- IF in8_reserve_pub = i.reserve_pub
- THEN
- ruuid8 = i.reserve_uuid;
- IF in8_reserve_pub
- NOT IN (in_reserve_pub
- ,in2_reserve_pub
- ,in3_reserve_pub
- ,in4_reserve_pub
- ,in5_reserve_pub
- ,in6_reserve_pub
- ,in7_reserve_pub)
- THEN
- out_reserve_found8 = FALSE;
- END IF;
- END IF;
- END IF;
- k=k+1;
- END LOOP;
-
- CLOSE curs_reserve_existed;
-
--- FIXME: must be changed to EXECUTE FORMAT!
- PERFORM pg_notify(in_notify, NULL);
- PERFORM pg_notify(in2_notify, NULL);
- PERFORM pg_notify(in3_notify, NULL);
- PERFORM pg_notify(in4_notify, NULL);
- PERFORM pg_notify(in5_notify, NULL);
- PERFORM pg_notify(in6_notify, NULL);
- PERFORM pg_notify(in7_notify, NULL);
- PERFORM pg_notify(in8_notify, NULL);
- k=0;
- OPEN curs_transaction_existed FOR
- WITH reserve_in_changes AS (
- INSERT INTO reserves_in
- (reserve_pub
- ,wire_reference
- ,credit_val
- ,credit_frac
- ,exchange_account_section
- ,wire_source_h_payto
- ,execution_date)
- VALUES
- (in_reserve_pub
- ,in_wire_ref
- ,in_credit_val
- ,in_credit_frac
- ,in_exchange_account_name
- ,in_wire_source_h_payto
- ,in_execution_date),
- (in2_reserve_pub
- ,in2_wire_ref
- ,in2_credit_val
- ,in2_credit_frac
- ,in2_exchange_account_name
- ,in2_wire_source_h_payto
- ,in_execution_date),
- (in3_reserve_pub
- ,in3_wire_ref
- ,in3_credit_val
- ,in3_credit_frac
- ,in3_exchange_account_name
- ,in3_wire_source_h_payto
- ,in_execution_date),
- (in4_reserve_pub
- ,in4_wire_ref
- ,in4_credit_val
- ,in4_credit_frac
- ,in4_exchange_account_name
- ,in4_wire_source_h_payto
- ,in_execution_date),
- (in5_reserve_pub
- ,in5_wire_ref
- ,in5_credit_val
- ,in5_credit_frac
- ,in5_exchange_account_name
- ,in5_wire_source_h_payto
- ,in_execution_date),
- (in6_reserve_pub
- ,in6_wire_ref
- ,in6_credit_val
- ,in6_credit_frac
- ,in6_exchange_account_name
- ,in6_wire_source_h_payto
- ,in_execution_date),
- (in7_reserve_pub
- ,in7_wire_ref
- ,in7_credit_val
- ,in7_credit_frac
- ,in7_exchange_account_name
- ,in7_wire_source_h_payto
- ,in_execution_date),
- (in8_reserve_pub
- ,in8_wire_ref
- ,in8_credit_val
- ,in8_credit_frac
- ,in8_exchange_account_name
- ,in8_wire_source_h_payto
- ,in_execution_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_pub)
- SELECT * FROM reserve_in_changes;
-
- WHILE k < 8 LOOP
- FETCH FROM curs_transaction_existed INTO r;
- IF FOUND
- THEN
- IF in_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate = FALSE;
- END IF;
- IF in2_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate2 = FALSE;
- END IF;
- IF in3_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate3 = FALSE;
- END IF;
- IF in4_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate4 = FALSE;
- END IF;
- IF in5_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate5 = FALSE;
- END IF;
- IF in6_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate6 = FALSE;
- END IF;
- IF in7_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate7 = FALSE;
- END IF;
- IF in8_reserve_pub = r.reserve_pub
- THEN
- transaction_duplicate8 = FALSE;
- END IF;
- END IF;
- k=k+1;
- END LOOP;
- /* IF transaction_duplicate
- OR transaction_duplicate2
- OR transaction_duplicate3
- OR transaction_duplicate4
- OR transaction_duplicate5
- OR transaction_duplicate6
- OR transaction_duplicate7
- OR transaction_duplicate8
- THEN
- CLOSE curs_transaction_existed;
- ROLLBACK;
- RETURN;
- END IF;*/
- CLOSE curs_transaction_existed;
- RETURN;
-END $$;
diff --git a/src/exchangedb/exchange_do_batch_coin_known.sql b/src/exchangedb/exchange_do_batch_coin_known.sql
new file mode 100644
index 000000000..db96cb08c
--- /dev/null
+++ b/src/exchangedb/exchange_do_batch_coin_known.sql
@@ -0,0 +1,469 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2022 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE OR REPLACE FUNCTION exchange_do_batch4_known_coin(
+ IN in_coin_pub1 BYTEA,
+ IN in_denom_pub_hash1 BYTEA,
+ IN in_h_age_commitment1 BYTEA,
+ IN in_denom_sig1 BYTEA,
+ IN in_coin_pub2 BYTEA,
+ IN in_denom_pub_hash2 BYTEA,
+ IN in_h_age_commitment2 BYTEA,
+ IN in_denom_sig2 BYTEA,
+ IN in_coin_pub3 BYTEA,
+ IN in_denom_pub_hash3 BYTEA,
+ IN in_h_age_commitment3 BYTEA,
+ IN in_denom_sig3 BYTEA,
+ IN in_coin_pub4 BYTEA,
+ IN in_denom_pub_hash4 BYTEA,
+ IN in_h_age_commitment4 BYTEA,
+ IN in_denom_sig4 BYTEA,
+ OUT existed1 BOOLEAN,
+ OUT existed2 BOOLEAN,
+ OUT existed3 BOOLEAN,
+ OUT existed4 BOOLEAN,
+ OUT known_coin_id1 INT8,
+ OUT known_coin_id2 INT8,
+ OUT known_coin_id3 INT8,
+ OUT known_coin_id4 INT8,
+ OUT denom_pub_hash1 BYTEA,
+ OUT denom_pub_hash2 BYTEA,
+ OUT denom_pub_hash3 BYTEA,
+ OUT denom_pub_hash4 BYTEA,
+ OUT age_commitment_hash1 BYTEA,
+ OUT age_commitment_hash2 BYTEA,
+ OUT age_commitment_hash3 BYTEA,
+ OUT age_commitment_hash4 BYTEA)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+WITH dd AS (
+SELECT
+ denominations_serial,
+ coin
+ FROM denominations
+ WHERE denom_pub_hash
+ IN
+ (in_denom_pub_hash1,
+ in_denom_pub_hash2,
+ in_denom_pub_hash3,
+ in_denom_pub_hash4)
+ ),--dd
+ input_rows AS (
+ VALUES
+ (in_coin_pub1,
+ in_denom_pub_hash1,
+ in_h_age_commitment1,
+ in_denom_sig1),
+ (in_coin_pub2,
+ in_denom_pub_hash2,
+ in_h_age_commitment2,
+ in_denom_sig2),
+ (in_coin_pub3,
+ in_denom_pub_hash3,
+ in_h_age_commitment3,
+ in_denom_sig3),
+ (in_coin_pub4,
+ in_denom_pub_hash4,
+ in_h_age_commitment4,
+ in_denom_sig4)
+ ),--ir
+ ins AS (
+ INSERT INTO known_coins (
+ coin_pub,
+ denominations_serial,
+ age_commitment_hash,
+ denom_sig,
+ remaining
+ )
+ SELECT
+ ir.coin_pub,
+ dd.denominations_serial,
+ ir.age_commitment_hash,
+ ir.denom_sig,
+ dd.coin
+ FROM input_rows ir
+ JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ ON CONFLICT DO NOTHING
+ RETURNING known_coin_id
+ ),--kc
+ exists AS (
+ SELECT
+ CASE
+ WHEN
+ ins.known_coin_id IS NOT NULL
+ THEN
+ FALSE
+ ELSE
+ TRUE
+ END AS existed,
+ ins.known_coin_id,
+ dd.denom_pub_hash,
+ kc.age_commitment_hash
+ FROM input_rows ir
+ LEFT JOIN ins
+ ON ins.coin_pub = ir.coin_pub
+ LEFT JOIN known_coins kc
+ ON kc.coin_pub = ir.coin_pub
+ LEFT JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ )--exists
+SELECT
+ exists.existed AS existed1,
+ exists.known_coin_id AS known_coin_id1,
+ exists.denom_pub_hash AS denom_pub_hash1,
+ exists.age_commitment_hash AS age_commitment_hash1,
+ (
+ SELECT exists.existed
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS existed2,
+ (
+ SELECT exists.known_coin_id
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS known_coin_id2,
+ (
+ SELECT exists.denom_pub_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS denom_pub_hash2,
+ (
+ SELECT exists.age_commitment_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ )AS age_commitment_hash2,
+ (
+ SELECT exists.existed
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash3
+ ) AS existed3,
+ (
+ SELECT exists.known_coin_id
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash3
+ ) AS known_coin_id3,
+ (
+ SELECT exists.denom_pub_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash3
+ ) AS denom_pub_hash3,
+ (
+ SELECT exists.age_commitment_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash3
+ )AS age_commitment_hash3,
+ (
+ SELECT exists.existed
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash4
+ ) AS existed4,
+ (
+ SELECT exists.known_coin_id
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash4
+ ) AS known_coin_id4,
+ (
+ SELECT exists.denom_pub_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash4
+ ) AS denom_pub_hash4,
+ (
+ SELECT exists.age_commitment_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash4
+ )AS age_commitment_hash4
+FROM exists;
+
+RETURN;
+END $$;
+
+
+CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin(
+ IN in_coin_pub1 BYTEA,
+ IN in_denom_pub_hash1 BYTEA,
+ IN in_h_age_commitment1 BYTEA,
+ IN in_denom_sig1 BYTEA,
+ IN in_coin_pub2 BYTEA,
+ IN in_denom_pub_hash2 BYTEA,
+ IN in_h_age_commitment2 BYTEA,
+ IN in_denom_sig2 BYTEA,
+ OUT existed1 BOOLEAN,
+ OUT existed2 BOOLEAN,
+ OUT known_coin_id1 INT8,
+ OUT known_coin_id2 INT8,
+ OUT denom_pub_hash1 BYTEA,
+ OUT denom_pub_hash2 BYTEA,
+ OUT age_commitment_hash1 BYTEA,
+ OUT age_commitment_hash2 BYTEA)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+WITH dd AS (
+SELECT
+ denominations_serial,
+ coin
+ FROM denominations
+ WHERE denom_pub_hash
+ IN
+ (in_denom_pub_hash1,
+ in_denom_pub_hash2)
+ ),--dd
+ input_rows AS (
+ VALUES
+ (in_coin_pub1,
+ in_denom_pub_hash1,
+ in_h_age_commitment1,
+ in_denom_sig1),
+ (in_coin_pub2,
+ in_denom_pub_hash2,
+ in_h_age_commitment2,
+ in_denom_sig2)
+ ),--ir
+ ins AS (
+ INSERT INTO known_coins (
+ coin_pub,
+ denominations_serial,
+ age_commitment_hash,
+ denom_sig,
+ remaining
+ )
+ SELECT
+ ir.coin_pub,
+ dd.denominations_serial,
+ ir.age_commitment_hash,
+ ir.denom_sig,
+ dd.coin
+ FROM input_rows ir
+ JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ ON CONFLICT DO NOTHING
+ RETURNING known_coin_id
+ ),--kc
+ exists AS (
+ SELECT
+ CASE
+ WHEN ins.known_coin_id IS NOT NULL
+ THEN
+ FALSE
+ ELSE
+ TRUE
+ END AS existed,
+ ins.known_coin_id,
+ dd.denom_pub_hash,
+ kc.age_commitment_hash
+ FROM input_rows ir
+ LEFT JOIN ins
+ ON ins.coin_pub = ir.coin_pub
+ LEFT JOIN known_coins kc
+ ON kc.coin_pub = ir.coin_pub
+ LEFT JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ )--exists
+SELECT
+ exists.existed AS existed1,
+ exists.known_coin_id AS known_coin_id1,
+ exists.denom_pub_hash AS denom_pub_hash1,
+ exists.age_commitment_hash AS age_commitment_hash1,
+ (
+ SELECT exists.existed
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS existed2,
+ (
+ SELECT exists.known_coin_id
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS known_coin_id2,
+ (
+ SELECT exists.denom_pub_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ ) AS denom_pub_hash2,
+ (
+ SELECT exists.age_commitment_hash
+ FROM exists
+ WHERE exists.denom_pub_hash = in_denom_pub_hash2
+ )AS age_commitment_hash2
+FROM exists;
+
+RETURN;
+END $$;
+
+
+CREATE OR REPLACE FUNCTION exchange_do_batch1_known_coin(
+ IN in_coin_pub1 BYTEA,
+ IN in_denom_pub_hash1 BYTEA,
+ IN in_h_age_commitment1 BYTEA,
+ IN in_denom_sig1 BYTEA,
+ OUT existed1 BOOLEAN,
+ OUT known_coin_id1 INT8,
+ OUT denom_pub_hash1 BYTEA,
+ OUT age_commitment_hash1 BYTEA)
+LANGUAGE plpgsql
+AS $$
+BEGIN
+WITH dd AS (
+SELECT
+ denominations_serial,
+ coin
+ FROM denominations
+ WHERE denom_pub_hash
+ IN
+ (in_denom_pub_hash1,
+ in_denom_pub_hash2)
+ ),--dd
+ input_rows AS (
+ VALUES
+ (in_coin_pub1,
+ in_denom_pub_hash1,
+ in_h_age_commitment1,
+ in_denom_sig1)
+ ),--ir
+ ins AS (
+ INSERT INTO known_coins (
+ coin_pub,
+ denominations_serial,
+ age_commitment_hash,
+ denom_sig,
+ remaining
+ )
+ SELECT
+ ir.coin_pub,
+ dd.denominations_serial,
+ ir.age_commitment_hash,
+ ir.denom_sig,
+ dd.coin
+ FROM input_rows ir
+ JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ ON CONFLICT DO NOTHING
+ RETURNING known_coin_id
+ ),--kc
+ exists AS (
+ SELECT
+ CASE
+ WHEN ins.known_coin_id IS NOT NULL
+ THEN
+ FALSE
+ ELSE
+ TRUE
+ END AS existed,
+ ins.known_coin_id,
+ dd.denom_pub_hash,
+ kc.age_commitment_hash
+ FROM input_rows ir
+ LEFT JOIN ins
+ ON ins.coin_pub = ir.coin_pub
+ LEFT JOIN known_coins kc
+ ON kc.coin_pub = ir.coin_pub
+ LEFT JOIN dd
+ ON dd.denom_pub_hash = ir.denom_pub_hash
+ )--exists
+SELECT
+ exists.existed AS existed1,
+ exists.known_coin_id AS known_coin_id1,
+ exists.denom_pub_hash AS denom_pub_hash1,
+ exists.age_commitment_hash AS age_commitment_hash1
+FROM exists;
+
+RETURN;
+END $$;
+
+/*** Experiment using a loop ***/
+/*
+CREATE OR REPLACE FUNCTION exchange_do_batch2_known_coin(
+ IN in_coin_pub1 BYTEA,
+ IN in_denom_pub_hash1 TEXT,
+ IN in_h_age_commitment1 TEXT,
+ IN in_denom_sig1 TEXT,
+ IN in_coin_pub2 BYTEA,
+ IN in_denom_pub_hash2 TEXT,
+ IN in_h_age_commitment2 TEXT,
+ IN in_denom_sig2 TEXT,
+ OUT existed1 BOOLEAN,
+ OUT existed2 BOOLEAN,
+ OUT known_coin_id1 INT8,
+ OUT known_coin_id2 INT8,
+ OUT denom_pub_hash1 TEXT,
+ OUT denom_pub_hash2 TEXT,
+ OUT age_commitment_hash1 TEXT,
+ OUT age_commitment_hash2 TEXT)
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ ins_values RECORD;
+BEGIN
+ FOR i IN 1..2 LOOP
+ ins_values := (
+ SELECT
+ in_coin_pub1 AS coin_pub,
+ in_denom_pub_hash1 AS denom_pub_hash,
+ in_h_age_commitment1 AS age_commitment_hash,
+ in_denom_sig1 AS denom_sig
+ WHERE i = 1
+ UNION
+ SELECT
+ in_coin_pub2 AS coin_pub,
+ in_denom_pub_hash2 AS denom_pub_hash,
+ in_h_age_commitment2 AS age_commitment_hash,
+ in_denom_sig2 AS denom_sig
+ WHERE i = 2
+ );
+ WITH dd (denominations_serial, coin) AS (
+ SELECT denominations_serial, coin
+ FROM denominations
+ WHERE denom_pub_hash = ins_values.denom_pub_hash
+ ),
+ input_rows(coin_pub) AS (
+ VALUES (ins_values.coin_pub)
+ ),
+ ins AS (
+ INSERT INTO known_coins (
+ coin_pub,
+ denominations_serial,
+ age_commitment_hash,
+ denom_sig,
+ remaining
+ ) SELECT
+ input_rows.coin_pub,
+ dd.denominations_serial,
+ ins_values.age_commitment_hash,
+ ins_values.denom_sig,
+ coin
+ FROM dd
+ CROSS JOIN input_rows
+ ON CONFLICT DO NOTHING
+ RETURNING known_coin_id, denom_pub_hash
+ )
+ SELECT
+ CASE i
+ WHEN 1 THEN
+ COALESCE(ins.known_coin_id, 0) <> 0 AS existed1,
+ ins.known_coin_id AS known_coin_id1,
+ ins.denom_pub_hash AS denom_pub_hash1,
+ ins.age_commitment_hash AS age_commitment_hash1
+ WHEN 2 THEN
+ COALESCE(ins.known_coin_id, 0) <> 0 AS existed2,
+ ins.known_coin_id AS known_coin_id2,
+ ins.denom_pub_hash AS denom_pub_hash2,
+ ins.age_commitment_hash AS age_commitment_hash2
+ END
+ FROM ins;
+ END LOOP;
+END;
+$$;*/
diff --git a/src/exchangedb/exchange_do_batch_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch_reserves_in_insert.sql
deleted file mode 100644
index 4eec2e006..000000000
--- a/src/exchangedb/exchange_do_batch_reserves_in_insert.sql
+++ /dev/null
@@ -1,119 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert(
- IN in_reserve_pub BYTEA,
- IN in_expiration_date INT8,
- IN in_gc_date INT8,
- IN in_wire_ref INT8,
- IN in_credit_val INT8,
- IN in_credit_frac INT4,
- IN in_exchange_account_name VARCHAR,
- IN in_execution_date INT8,
- IN in_wire_source_h_payto BYTEA, ---h_payto
- IN in_payto_uri VARCHAR,
- IN in_reserve_expiration INT8,
- IN in_notify text,
- OUT out_reserve_found BOOLEAN,
- OUT transaction_duplicate BOOLEAN,
- OUT ruuid INT8)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs refcursor;
-DECLARE
- i RECORD;
-DECLARE
- curs_trans refcursor;
-BEGIN
- ruuid = 0;
- out_reserve_found = TRUE;
- transaction_duplicate = TRUE;
-
---SIMPLE INSERT ON CONFLICT DO NOTHING
- INSERT INTO wire_targets
- (wire_target_h_payto
- ,payto_uri)
- VALUES
- (in_wire_source_h_payto
- ,in_payto_uri)
- ON CONFLICT DO NOTHING;
-
- OPEN curs FOR
- WITH reserve_changes AS (
- INSERT INTO reserves
- (reserve_pub
- ,current_balance_val
- ,current_balance_frac
- ,expiration_date
- ,gc_date)
- VALUES
- (in_reserve_pub
- ,in_credit_val
- ,in_credit_frac
- ,in_expiration_date
- ,in_gc_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_uuid, reserve_pub)
- SELECT * FROM reserve_changes;
- FETCH FROM curs INTO i;
- IF FOUND
- THEN
- -- We made a change, so the reserve did not previously exist.
- IF in_reserve_pub = i.reserve_pub
- THEN
- out_reserve_found = FALSE;
- ruuid = i.reserve_uuid;
- END IF;
- END IF;
- CLOSE curs;
-
- OPEN curs_trans FOR
- WITH reserve_transaction AS(
- INSERT INTO reserves_in
- (reserve_pub
- ,wire_reference
- ,credit_val
- ,credit_frac
- ,exchange_account_section
- ,wire_source_h_payto
- ,execution_date)
- VALUES
- (in_reserve_pub
- ,in_wire_ref
- ,in_credit_val
- ,in_credit_frac
- ,in_exchange_account_name
- ,in_wire_source_h_payto
- ,in_execution_date)
- ON CONFLICT DO NOTHING
- RETURNING reserve_pub)
- SELECT * FROM reserve_transaction;
- FETCH FROM curs_trans INTO i;
- IF FOUND
- THEN
- IF i.reserve_pub = in_reserve_pub
- THEN
- -- HAPPY PATH THERE IS NO DUPLICATE TRANS
- transaction_duplicate = FALSE;
- EXECUTE FORMAT (
- 'NOTIFY %s'
- ,in_notify);
- END IF;
- END IF;
- CLOSE curs_trans;
- RETURN;
-END $$;
diff --git a/src/exchangedb/exchange_do_batch_reserves_update.sql b/src/exchangedb/exchange_do_batch_reserves_update.sql
index 82b6b84c1..ebb58a149 100644
--- a/src/exchangedb/exchange_do_batch_reserves_update.sql
+++ b/src/exchangedb/exchange_do_batch_reserves_update.sql
@@ -18,9 +18,8 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_update(
IN in_reserve_pub BYTEA,
IN in_expiration_date INT8,
IN in_wire_ref INT8,
- IN in_credit_val INT8,
- IN in_credit_frac INT4,
- IN in_exchange_account_name VARCHAR,
+ IN in_credit taler_amount,
+ IN in_exchange_account_name TEXT,
IN in_wire_source_h_payto BYTEA,
IN in_notify text,
OUT out_duplicate BOOLEAN)
@@ -30,16 +29,14 @@ BEGIN
INSERT INTO reserves_in
(reserve_pub
,wire_reference
- ,credit_val
- ,credit_frac
+ ,credit
,exchange_account_section
,wire_source_h_payto
,execution_date)
VALUES
(in_reserve_pub
,in_wire_ref
- ,in_credit_val
- ,in_credit_frac
+ ,in_credit
,in_exchange_account_name
,in_wire_source_h_payto
,in_expiration_date)
@@ -48,24 +45,26 @@ BEGIN
THEN
--IF THE INSERTION WAS A SUCCESS IT MEANS NO DUPLICATED TRANSACTION
out_duplicate = FALSE;
- UPDATE reserves
+ UPDATE reserves rs
SET
- current_balance_frac = current_balance_frac+in_credit_frac
+ current_balance.frac = (rs.current_balance).frac+in_credit.frac
- CASE
- WHEN current_balance_frac + in_credit_frac >= 100000000
+ WHEN (rs.current_balance).frac + in_credit.frac >= 100000000
THEN 100000000
ELSE 1
END
- ,current_balance_val = current_balance_val+in_credit_val
+ ,current_balance.val = (rs.current_balance).val+in_credit.val
+ CASE
- WHEN current_balance_frac + in_credit_frac >= 100000000
+ WHEN (rs.current_balance).frac + in_credit.frac >= 100000000
THEN 1
ELSE 0
END
,expiration_date=GREATEST(expiration_date,in_expiration_date)
,gc_date=GREATEST(gc_date,in_expiration_date)
WHERE reserve_pub=in_reserve_pub;
- PERFORM pg_notify(in_notify, NULL);
+ EXECUTE FORMAT (
+ 'NOTIFY %s'
+ ,in_notify);
ELSE
out_duplicate = TRUE;
END IF;
diff --git a/src/exchangedb/exchange_do_batch_withdraw.sql b/src/exchangedb/exchange_do_batch_withdraw.sql
index fedb7e912..a48561a9a 100644
--- a/src/exchangedb/exchange_do_batch_withdraw.sql
+++ b/src/exchangedb/exchange_do_batch_withdraw.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -13,24 +13,27 @@
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
+-- @author Christian Grothoff
+-- @author Özgür Kesim
CREATE OR REPLACE FUNCTION exchange_do_batch_withdraw(
- IN amount_val INT8,
- IN amount_frac INT4,
+ IN amount taler_amount,
IN rpub BYTEA,
IN now INT8,
IN min_reserve_gc INT8,
+ IN do_age_check BOOLEAN,
OUT reserve_found BOOLEAN,
OUT balance_ok BOOLEAN,
+ OUT reserve_balance taler_amount,
+ OUT age_ok BOOLEAN,
+ OUT allowed_maximum_age INT2, -- in years
OUT ruuid INT8)
LANGUAGE plpgsql
AS $$
DECLARE
- reserve_gc INT8;
-DECLARE
- reserve_val INT8;
-DECLARE
- reserve_frac INT4;
+ reserve RECORD;
+ balance taler_amount;
+ not_before date;
BEGIN
-- Shards: reserves by reserve_pub (SELECT)
-- reserves_out (INSERT, with CONFLICT detection) by wih
@@ -38,16 +41,11 @@ BEGIN
-- reserves_in by reserve_pub (SELECT)
-- wire_targets by wire_target_h_payto
-SELECT
- current_balance_val
- ,current_balance_frac
- ,gc_date
- ,reserve_uuid
- INTO
- reserve_val
- ,reserve_frac
- ,reserve_gc
- ,ruuid
+SELECT current_balance
+ ,reserve_uuid
+ ,birthday
+ ,gc_date
+ INTO reserve
FROM exchange.reserves
WHERE reserves.reserve_pub=rpub;
@@ -56,51 +54,73 @@ THEN
-- reserve unknown
reserve_found=FALSE;
balance_ok=FALSE;
+ reserve_balance.frac = 0;
+ reserve_balance.val = 0;
+ age_ok=FALSE;
+ allowed_maximum_age=0;
ruuid=2;
RETURN;
END IF;
+reserve_found=TRUE;
+reserve_balance = reserve.current_balance;
+ruuid = reserve.reserve_uuid;
+
+-- Check if age requirements are present
+IF ((NOT do_age_check) OR (reserve.birthday = 0))
+THEN
+ age_ok = TRUE;
+ allowed_maximum_age = -1;
+ELSE
+ -- Age requirements are formally not met: The exchange is setup to support
+ -- age restrictions (do_age_check == TRUE) and the reserve has a
+ -- birthday set (reserve_birthday != 0), but the client called the
+ -- batch-withdraw endpoint instead of the age-withdraw endpoint, which it
+ -- should have.
+ not_before=date '1970-01-01' + reserve.birthday;
+ allowed_maximum_age = extract(year from age(current_date, not_before));
+
+ balance_ok=FALSE;
+ age_ok = FALSE;
+ RETURN;
+END IF;
+
-- Check reserve balance is sufficient.
-IF (reserve_val > amount_val)
+IF (reserve_balance.val > amount.val)
THEN
- IF (reserve_frac >= amount_frac)
+ IF (reserve_balance.frac >= amount.frac)
THEN
- reserve_val=reserve_val - amount_val;
- reserve_frac=reserve_frac - amount_frac;
+ balance.val=reserve_balance.val - amount.val;
+ balance.frac=reserve_balance.frac - amount.frac;
ELSE
- reserve_val=reserve_val - amount_val - 1;
- reserve_frac=reserve_frac + 100000000 - amount_frac;
+ balance.val=reserve_balance.val - amount.val - 1;
+ balance.frac=reserve_balance.frac + 100000000 - amount.frac;
END IF;
ELSE
- IF (reserve_val = amount_val) AND (reserve_frac >= amount_frac)
+ IF (reserve_balance.val = amount.val) AND (reserve_balance.frac >= amount.frac)
THEN
- reserve_val=0;
- reserve_frac=reserve_frac - amount_frac;
+ balance.val=0;
+ balance.frac=reserve_balance.frac - amount.frac;
ELSE
- reserve_found=TRUE;
balance_ok=FALSE;
RETURN;
END IF;
END IF;
-- Calculate new expiration dates.
-min_reserve_gc=GREATEST(min_reserve_gc,reserve_gc);
+min_reserve_gc=GREATEST(min_reserve_gc,reserve.gc_date);
-- Update reserve balance.
UPDATE reserves SET
gc_date=min_reserve_gc
- ,current_balance_val=reserve_val
- ,current_balance_frac=reserve_frac
+ ,current_balance=balance
WHERE
reserves.reserve_pub=rpub;
-reserve_found=TRUE;
balance_ok=TRUE;
END $$;
-COMMENT ON FUNCTION exchange_do_batch_withdraw(INT8, INT4, BYTEA, INT8, INT8)
- IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result. Excludes storing the planchets.';
-
-
+COMMENT ON FUNCTION exchange_do_batch_withdraw(taler_amount, BYTEA, INT8, INT8, BOOLEAN)
+ IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and that age requirements are formally met. If so updates the database with the result. Excludes storing the planchets.';
diff --git a/src/exchangedb/exchange_do_batch_withdraw_insert.sql b/src/exchangedb/exchange_do_batch_withdraw_insert.sql
index 98db840f9..d36181a6b 100644
--- a/src/exchangedb/exchange_do_batch_withdraw_insert.sql
+++ b/src/exchangedb/exchange_do_batch_withdraw_insert.sql
@@ -14,14 +14,10 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
-
-
-
CREATE OR REPLACE FUNCTION exchange_do_batch_withdraw_insert(
IN cs_nonce BYTEA,
- IN amount_val INT8,
- IN amount_frac INT4,
- IN h_denom_pub BYTEA,
+ IN amount taler_amount,
+ IN h_denom_pub BYTEA, -- FIXME: denom_serials should really be a parameter to this FUNCTION.
IN ruuid INT8,
IN reserve_sig BYTEA,
IN h_coin_envelope BYTEA,
@@ -45,6 +41,8 @@ out_denom_unknown=TRUE;
out_conflict=TRUE;
out_nonce_reuse=TRUE;
+-- FIXME: denom_serials should really be a parameter to this FUNCTION.
+
SELECT denominations_serial
INTO denom_serial
FROM exchange.denominations
@@ -66,8 +64,7 @@ INSERT INTO exchange.reserves_out
,reserve_uuid
,reserve_sig
,execution_date
- ,amount_with_fee_val
- ,amount_with_fee_frac)
+ ,amount_with_fee)
VALUES
(h_coin_envelope
,denom_serial
@@ -75,8 +72,7 @@ VALUES
,ruuid
,reserve_sig
,now
- ,amount_val
- ,amount_frac)
+ ,amount)
ON CONFLICT DO NOTHING;
IF NOT FOUND
@@ -120,6 +116,5 @@ END IF;
END $$;
-COMMENT ON FUNCTION exchange_do_batch_withdraw_insert(BYTEA, INT8, INT4, BYTEA, INT8, BYTEA, BYTEA, BYTEA, INT8)
+COMMENT ON FUNCTION exchange_do_batch_withdraw_insert(BYTEA, taler_amount, BYTEA, INT8, BYTEA, BYTEA, BYTEA, INT8)
IS 'Stores information about a planchet for a batch withdraw operation. Checks if the planchet already exists, and in that case indicates a conflict';
-
diff --git a/src/exchangedb/exchange_do_deposit.sql b/src/exchangedb/exchange_do_deposit.sql
index a2f5ba53a..c89e9e470 100644
--- a/src/exchangedb/exchange_do_deposit.sql
+++ b/src/exchangedb/exchange_do_deposit.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -14,158 +14,193 @@
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
CREATE OR REPLACE FUNCTION exchange_do_deposit(
- IN in_amount_with_fee_val INT8,
- IN in_amount_with_fee_frac INT4,
- IN in_h_contract_terms BYTEA,
- IN in_wire_salt BYTEA,
+ -- For batch_deposits
+ IN in_shard INT8,
+ IN in_merchant_pub BYTEA,
IN in_wallet_timestamp INT8,
IN in_exchange_timestamp INT8,
IN in_refund_deadline INT8,
IN in_wire_deadline INT8,
- IN in_merchant_pub BYTEA,
- IN in_receiver_wire_account VARCHAR,
- IN in_h_payto BYTEA,
- IN in_known_coin_id INT8,
- IN in_coin_pub BYTEA,
- IN in_coin_sig BYTEA,
- IN in_shard INT8,
+ IN in_h_contract_terms BYTEA,
+ IN in_wallet_data_hash BYTEA, -- can be NULL
+ IN in_wire_salt BYTEA,
+ IN in_wire_target_h_payto BYTEA,
+ IN in_policy_details_serial_id INT8, -- can be NULL
IN in_policy_blocked BOOLEAN,
- IN in_policy_details_serial_id INT8,
+ -- For wire_targets
+ IN in_receiver_wire_account TEXT,
+ -- For coin_deposits
+ IN ina_coin_pub BYTEA[],
+ IN ina_coin_sig BYTEA[],
+ IN ina_amount_with_fee taler_amount[],
OUT out_exchange_timestamp INT8,
- OUT out_balance_ok BOOLEAN,
- OUT out_conflict BOOLEAN)
+ OUT out_insufficient_balance_coin_index INT4, -- index of coin with bad balance, NULL if none
+ OUT out_conflict BOOL
+ )
LANGUAGE plpgsql
AS $$
DECLARE
wtsi INT8; -- wire target serial id
+ bdsi INT8; -- batch_deposits serial id
+ i INT4;
+ ini_amount_with_fee taler_amount;
+ ini_coin_pub BYTEA;
+ ini_coin_sig BYTEA;
BEGIN
--- Shards: INSERT policy_details (by policy_details_serial_id)
--- INSERT wire_targets (by h_payto), on CONFLICT DO NOTHING;
--- INSERT deposits (by coin_pub, shard), ON CONFLICT DO NOTHING;
--- UPDATE known_coins (by coin_pub)
+-- Shards:
+-- INSERT wire_targets (by h_payto), ON CONFLICT DO NOTHING;
+-- INSERT batch_deposits (by shard, merchant_pub), ON CONFLICT idempotency check;
+-- INSERT[] coin_deposits (by coin_pub), ON CONFLICT idempotency check;
+-- UPDATE[] known_coins (by coin_pub)
+
-INSERT INTO exchange.wire_targets
- (wire_target_h_payto
- ,payto_uri)
+-- First, get or create the 'wtsi'
+INSERT INTO wire_targets
+ (wire_target_h_payto
+ ,payto_uri)
VALUES
- (in_h_payto
- ,in_receiver_wire_account)
-ON CONFLICT DO NOTHING -- for CONFLICT ON (wire_target_h_payto)
- RETURNING wire_target_serial_id INTO wtsi;
+ (in_wire_target_h_payto
+ ,in_receiver_wire_account)
+ ON CONFLICT DO NOTHING -- for CONFLICT ON (wire_target_h_payto)
+ RETURNING
+ wire_target_serial_id
+ INTO
+ wtsi;
IF NOT FOUND
THEN
- SELECT wire_target_serial_id
- INTO wtsi
- FROM exchange.wire_targets
- WHERE wire_target_h_payto=in_h_payto;
+ SELECT
+ wire_target_serial_id
+ INTO
+ wtsi
+ FROM wire_targets
+ WHERE
+ wire_target_h_payto=in_wire_target_h_payto;
END IF;
-INSERT INTO exchange.deposits
+-- Second, create the batch_deposits entry
+INSERT INTO batch_deposits
(shard
- ,coin_pub
- ,known_coin_id
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,merchant_pub
,wallet_timestamp
,exchange_timestamp
,refund_deadline
,wire_deadline
- ,merchant_pub
,h_contract_terms
- ,coin_sig
+ ,wallet_data_hash
,wire_salt
,wire_target_h_payto
- ,policy_blocked
,policy_details_serial_id
+ ,policy_blocked
)
VALUES
(in_shard
- ,in_coin_pub
- ,in_known_coin_id
- ,in_amount_with_fee_val
- ,in_amount_with_fee_frac
+ ,in_merchant_pub
,in_wallet_timestamp
,in_exchange_timestamp
,in_refund_deadline
,in_wire_deadline
- ,in_merchant_pub
,in_h_contract_terms
- ,in_coin_sig
+ ,in_wallet_data_hash
,in_wire_salt
- ,in_h_payto
- ,in_policy_blocked
- ,in_policy_details_serial_id)
- ON CONFLICT DO NOTHING;
+ ,in_wire_target_h_payto
+ ,in_policy_details_serial_id
+ ,in_policy_blocked)
+ ON CONFLICT DO NOTHING -- for CONFLICT ON (merchant_pub, h_contract_terms)
+ RETURNING
+ batch_deposit_serial_id
+ INTO
+ bdsi;
IF NOT FOUND
THEN
-- Idempotency check: see if an identical record exists.
- -- Note that by checking 'coin_sig', we implicitly check
- -- identity over everything that the signature covers.
- -- We do select over merchant_pub and wire_target_h_payto
- -- primarily here to maximally use the existing index.
+ -- We do select over merchant_pub, h_contract_terms and wire_target_h_payto
+ -- first to maximally increase the chance of using the existing index.
SELECT
- exchange_timestamp
+ exchange_timestamp
+ ,batch_deposit_serial_id
INTO
- out_exchange_timestamp
- FROM exchange.deposits
+ out_exchange_timestamp
+ ,bdsi
+ FROM batch_deposits
WHERE shard=in_shard
AND merchant_pub=in_merchant_pub
- AND wire_target_h_payto=in_h_payto
- AND coin_pub=in_coin_pub
- AND coin_sig=in_coin_sig;
- -- AND policy_details_serial_id=in_policy_details_serial_id; -- FIXME: is this required for idempotency?
-
+ AND h_contract_terms=in_h_contract_terms
+ AND wire_target_h_payto=in_wire_target_h_payto
+ -- now check the rest, too
+ AND ( (wallet_data_hash=in_wallet_data_hash) OR
+ (wallet_data_hash IS NULL AND in_wallet_data_hash IS NULL) )
+ AND wire_salt=in_wire_salt
+ AND wallet_timestamp=in_wallet_timestamp
+ AND refund_deadline=in_refund_deadline
+ AND wire_deadline=in_wire_deadline
+ AND ( (policy_details_serial_id=in_policy_details_serial_id) OR
+ (policy_details_serial_id IS NULL AND in_policy_details_serial_id IS NULL) );
IF NOT FOUND
THEN
- -- Deposit exists, but with differences. Not allowed.
- out_balance_ok=FALSE;
+ -- Deposit exists, but with *strange* differences. Not allowed.
out_conflict=TRUE;
RETURN;
END IF;
+END IF;
- -- Idempotent request known, return success.
- out_balance_ok=TRUE;
- out_conflict=FALSE;
+out_conflict=FALSE;
- RETURN;
-END IF;
+-- Deposit each coin
+FOR i IN 1..array_length(ina_coin_pub,1)
+LOOP
+ ini_coin_pub = ina_coin_pub[i];
+ ini_coin_sig = ina_coin_sig[i];
+ ini_amount_with_fee = ina_amount_with_fee[i];
-out_exchange_timestamp=in_exchange_timestamp;
+ INSERT INTO coin_deposits
+ (batch_deposit_serial_id
+ ,coin_pub
+ ,coin_sig
+ ,amount_with_fee
+ )
+ VALUES
+ (bdsi
+ ,ini_coin_pub
+ ,ini_coin_sig
+ ,ini_amount_with_fee
+ )
+ ON CONFLICT DO NOTHING;
--- Check and update balance of the coin.
-UPDATE known_coins
- SET
- remaining_frac=remaining_frac-in_amount_with_fee_frac
- + CASE
- WHEN remaining_frac < in_amount_with_fee_frac
- THEN 100000000
- ELSE 0
- END,
- remaining_val=remaining_val-in_amount_with_fee_val
- - CASE
- WHEN remaining_frac < in_amount_with_fee_frac
- THEN 1
- ELSE 0
- END
- WHERE coin_pub=in_coin_pub
- AND ( (remaining_val > in_amount_with_fee_val) OR
- ( (remaining_frac >= in_amount_with_fee_frac) AND
- (remaining_val >= in_amount_with_fee_val) ) );
+ IF FOUND
+ THEN
+ -- Insert did happen, update balance in known_coins!
-IF NOT FOUND
-THEN
- -- Insufficient balance.
- out_balance_ok=FALSE;
- out_conflict=FALSE;
- RETURN;
-END IF;
+ UPDATE known_coins kc
+ SET
+ remaining.frac=(kc.remaining).frac-ini_amount_with_fee.frac
+ + CASE
+ WHEN (kc.remaining).frac < ini_amount_with_fee.frac
+ THEN 100000000
+ ELSE 0
+ END,
+ remaining.val=(kc.remaining).val-ini_amount_with_fee.val
+ - CASE
+ WHEN (kc.remaining).frac < ini_amount_with_fee.frac
+ THEN 1
+ ELSE 0
+ END
+ WHERE coin_pub=ini_coin_pub
+ AND ( ((kc.remaining).val > ini_amount_with_fee.val) OR
+ ( ((kc.remaining).frac >= ini_amount_with_fee.frac) AND
+ ((kc.remaining).val >= ini_amount_with_fee.val) ) );
--- Everything fine, return success!
-out_balance_ok=TRUE;
-out_conflict=FALSE;
+ IF NOT FOUND
+ THEN
+ -- Insufficient balance.
+ -- Note: C arrays are 0 indexed, but i started at 1
+ out_insufficient_balance_coin_index=i-1;
+ RETURN;
+ END IF;
+ END IF;
+END LOOP; -- end FOR all coins
END $$;
diff --git a/src/exchangedb/exchange_do_expire_purse.sql b/src/exchangedb/exchange_do_expire_purse.sql
index 82756abc5..ee9757f03 100644
--- a/src/exchangedb/exchange_do_expire_purse.sql
+++ b/src/exchangedb/exchange_do_expire_purse.sql
@@ -35,12 +35,11 @@ SELECT purse_pub
,in_reserve_quota
INTO my_purse_pub
,my_in_reserve_quota
- FROM exchange.purse_requests
+ FROM purse_requests
WHERE (purse_expiration >= in_start_time) AND
(purse_expiration < in_end_time) AND
- purse_pub NOT IN (SELECT purse_pub
- FROM purse_decision)
- ORDER BY purse_expiration ASC
+ NOT was_decided
+ ORDER BY purse_expiration ASC
LIMIT 1;
out_found = FOUND;
IF NOT FOUND
@@ -57,6 +56,9 @@ VALUES
,in_now
,TRUE);
+-- Code for 'TALER_DBEVENT_EXCHANGE_PURSE_REFUNDED'
+NOTIFY X8DJSPNYJMNZDAP7GN6YQ4EZVSQXMF3HRP4VAR347WP9SZYP1C200;
+
IF (my_in_reserve_quota)
THEN
UPDATE reserves
@@ -71,21 +73,20 @@ END IF;
-- restore balance to each coin deposited into the purse
FOR my_deposit IN
SELECT coin_pub
- ,amount_with_fee_val
- ,amount_with_fee_frac
- FROM exchange.purse_deposits
+ ,amount_with_fee
+ FROM purse_deposits
WHERE purse_pub = my_purse_pub
LOOP
- UPDATE exchange.known_coins SET
- remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac
+ UPDATE known_coins kc SET
+ remaining.frac=(kc.remaining).frac+(my_deposit.amount_with_fee).frac
- CASE
- WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000
+ WHEN (kc.remaining).frac+(my_deposit.amount_with_fee).frac >= 100000000
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val+my_deposit.amount_with_fee_val
+ remaining.val=(kc.remaining).val+(my_deposit.amount_with_fee).val
+ CASE
- WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000
+ WHEN (kc.remaining).frac+(my_deposit.amount_with_fee).frac >= 100000000
THEN 1
ELSE 0
END
@@ -95,5 +96,3 @@ END $$;
COMMENT ON FUNCTION exchange_do_expire_purse(INT8,INT8,INT8)
IS 'Finds an expired purse in the given time range and refunds the coins (if any).';
-
-
diff --git a/src/exchangedb/exchange_do_gc.sql b/src/exchangedb/exchange_do_gc.sql
index c6331c18e..d4ecb3024 100644
--- a/src/exchangedb/exchange_do_gc.sql
+++ b/src/exchangedb/exchange_do_gc.sql
@@ -21,124 +21,120 @@ LANGUAGE plpgsql
AS $$
DECLARE
reserve_uuid_min INT8; -- minimum reserve UUID still alive
-DECLARE
melt_min INT8; -- minimum melt still alive
-DECLARE
coin_min INT8; -- minimum known_coin still alive
-DECLARE
- deposit_min INT8; -- minimum deposit still alive
-DECLARE
+ batch_deposit_min INT8; -- minimum deposit still alive
reserve_out_min INT8; -- minimum reserve_out still alive
-DECLARE
denom_min INT8; -- minimum denomination still alive
BEGIN
-DELETE FROM exchange.prewire
+DELETE FROM prewire
WHERE finished=TRUE;
-DELETE FROM exchange.wire_fee
+DELETE FROM wire_fee
WHERE end_date < in_ancient_date;
--- TODO: use closing fee as threshold?
-DELETE FROM exchange.reserves
+-- FIXME: use closing fee as threshold?
+DELETE FROM reserves
WHERE gc_date < in_now
- AND current_balance_val = 0
- AND current_balance_frac = 0;
+ AND current_balance = (0, 0);
SELECT
reserve_out_serial_id
INTO
reserve_out_min
- FROM exchange.reserves_out
+ FROM reserves_out
ORDER BY reserve_out_serial_id ASC
LIMIT 1;
-DELETE FROM exchange.recoup
+DELETE FROM recoup
WHERE reserve_out_serial_id < reserve_out_min;
--- FIXME: recoup_refresh lacks GC!
SELECT
reserve_uuid
INTO
reserve_uuid_min
- FROM exchange.reserves
+ FROM reserves
ORDER BY reserve_uuid ASC
LIMIT 1;
-DELETE FROM exchange.reserves_out
+DELETE FROM reserves_out
WHERE reserve_uuid < reserve_uuid_min;
-- FIXME: this query will be horribly slow;
-- need to find another way to formulate it...
-DELETE FROM exchange.denominations
+DELETE FROM denominations
WHERE expire_legal < in_now
AND denominations_serial NOT IN
(SELECT DISTINCT denominations_serial
- FROM exchange.reserves_out)
+ FROM reserves_out)
AND denominations_serial NOT IN
(SELECT DISTINCT denominations_serial
- FROM exchange.known_coins
+ FROM known_coins
WHERE coin_pub IN
(SELECT DISTINCT coin_pub
- FROM exchange.recoup))
+ FROM recoup))
AND denominations_serial NOT IN
(SELECT DISTINCT denominations_serial
- FROM exchange.known_coins
+ FROM known_coins
WHERE coin_pub IN
(SELECT DISTINCT coin_pub
- FROM exchange.recoup_refresh));
+ FROM recoup_refresh));
SELECT
melt_serial_id
INTO
melt_min
- FROM exchange.refresh_commitments
+ FROM refresh_commitments
ORDER BY melt_serial_id ASC
LIMIT 1;
-DELETE FROM exchange.refresh_revealed_coins
+DELETE FROM refresh_revealed_coins
WHERE melt_serial_id < melt_min;
-DELETE FROM exchange.refresh_transfer_keys
+DELETE FROM refresh_transfer_keys
WHERE melt_serial_id < melt_min;
SELECT
known_coin_id
INTO
coin_min
- FROM exchange.known_coins
+ FROM known_coins
ORDER BY known_coin_id ASC
LIMIT 1;
-DELETE FROM exchange.deposits
+DELETE FROM recoup_refresh
WHERE known_coin_id < coin_min;
+DELETE FROM batch_deposits
+ WHERE wire_deadline < in_ancient_date;
+
SELECT
- deposit_serial_id
+ batch_deposit_serial_id
INTO
- deposit_min
- FROM exchange.deposits
- ORDER BY deposit_serial_id ASC
+ batch_deposit_min
+ FROM coin_deposits
+ ORDER BY batch_deposit_serial_id ASC
LIMIT 1;
-DELETE FROM exchange.refunds
- WHERE deposit_serial_id < deposit_min;
+DELETE FROM refunds
+ WHERE batch_deposit_serial_id < batch_deposit_min;
+DELETE FROM aggregation_tracking
+ WHERE batch_deposit_serial_id < batch_deposit_min;
+DELETE FROM coin_deposits
+ WHERE batch_deposit_serial_id < batch_deposit_min;
+
-DELETE FROM exchange.aggregation_tracking
- WHERE deposit_serial_id < deposit_min;
SELECT
denominations_serial
INTO
denom_min
- FROM exchange.denominations
+ FROM denominations
ORDER BY denominations_serial ASC
LIMIT 1;
-DELETE FROM exchange.cs_nonce_locks
+DELETE FROM cs_nonce_locks
WHERE max_denomination_serial <= denom_min;
END $$;
-
-
-
diff --git a/src/exchangedb/exchange_do_get_ready_deposit.sql b/src/exchangedb/exchange_do_get_ready_deposit.sql
deleted file mode 100644
index 001b69cb8..000000000
--- a/src/exchangedb/exchange_do_get_ready_deposit.sql
+++ /dev/null
@@ -1,69 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-CREATE OR REPLACE FUNCTION exchange_do_get_ready_deposit(
- IN in_now INT8,
- IN in_start_shard_now INT8,
- IN in_end_shard_now INT8,
- OUT out_payto_uri VARCHAR,
- OUT out_merchant_pub BYTEA
-)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- var_wire_target_h_payto BYTEA;
-DECLARE
- var_coin_pub BYTEA;
-DECLARE
- var_deposit_serial_id INT8;
-DECLARE
- curs CURSOR
- FOR
- SELECT
- coin_pub
- ,deposit_serial_id
- ,wire_deadline
- ,shard
- FROM deposits_by_ready
- WHERE wire_deadline <= in_now
- AND shard >=in_start_shard_now
- AND shard <=in_end_shard_now
- LIMIT 1;
-DECLARE
- i RECORD;
-BEGIN
-OPEN curs;
-FETCH FROM curs INTO i;
-IF NOT FOUND
-THEN
- RETURN;
-END IF;
-SELECT
- payto_uri
- ,merchant_pub
- INTO
- out_payto_uri
- ,out_merchant_pub
- FROM deposits dep
- JOIN wire_targets wt
- ON (wt.wire_target_h_payto=dep.wire_target_h_payto)
- WHERE dep.coin_pub=i.coin_pub
- AND dep.deposit_serial_id=i.deposit_serial_id
- ORDER BY
- i.wire_deadline ASC
- ,i.shard ASC;
-
-RETURN;
-END $$;
diff --git a/src/exchangedb/exchange_do_history_request.sql b/src/exchangedb/exchange_do_history_request.sql
deleted file mode 100644
index 2f6041741..000000000
--- a/src/exchangedb/exchange_do_history_request.sql
+++ /dev/null
@@ -1,85 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-
-CREATE OR REPLACE FUNCTION exchange_do_history_request(
- IN in_reserve_pub BYTEA,
- IN in_reserve_sig BYTEA,
- IN in_request_timestamp INT8,
- IN in_history_fee_val INT8,
- IN in_history_fee_frac INT4,
- OUT out_balance_ok BOOLEAN,
- OUT out_idempotent BOOLEAN)
-LANGUAGE plpgsql
-AS $$
-BEGIN
-
- -- Insert and check for idempotency.
- INSERT INTO exchange.history_requests
- (reserve_pub
- ,request_timestamp
- ,reserve_sig
- ,history_fee_val
- ,history_fee_frac)
- VALUES
- (in_reserve_pub
- ,in_request_timestamp
- ,in_reserve_sig
- ,in_history_fee_val
- ,in_history_fee_frac)
- ON CONFLICT DO NOTHING;
-
- IF NOT FOUND
- THEN
- out_balance_ok=TRUE;
- out_idempotent=TRUE;
- RETURN;
- END IF;
-
- out_idempotent=FALSE;
-
- -- Update reserve balance.
- UPDATE exchange.reserves
- SET
- current_balance_frac=current_balance_frac-in_history_fee_frac
- + CASE
- WHEN current_balance_frac < in_history_fee_frac
- THEN 100000000
- ELSE 0
- END,
- current_balance_val=current_balance_val-in_history_fee_val
- - CASE
- WHEN current_balance_frac < in_history_fee_frac
- THEN 1
- ELSE 0
- END
- WHERE
- reserve_pub=in_reserve_pub
- AND ( (current_balance_val > in_history_fee_val) OR
- ( (current_balance_frac >= in_history_fee_frac) AND
- (current_balance_val >= in_history_fee_val) ) );
-
- IF NOT FOUND
- THEN
- -- Either reserve does not exist, or balance insufficient.
- -- Both we treat the same here as balance insufficient.
- out_balance_ok=FALSE;
- RETURN;
- END IF;
-
- out_balance_ok=TRUE;
-END $$;
-
diff --git a/src/exchangedb/exchange_do_insert_aml_decision.sql b/src/exchangedb/exchange_do_insert_aml_decision.sql
index ef3e60048..c8ed7e928 100644
--- a/src/exchangedb/exchange_do_insert_aml_decision.sql
+++ b/src/exchangedb/exchange_do_insert_aml_decision.sql
@@ -16,13 +16,15 @@
CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision(
IN in_h_payto BYTEA,
- IN in_new_threshold_val INT8,
- IN in_new_threshold_frac INT4,
+ IN in_new_threshold taler_amount,
IN in_new_status INT4,
IN in_decision_time INT8,
- IN in_justification VARCHAR,
+ IN in_justification TEXT,
IN in_decider_pub BYTEA,
IN in_decider_sig BYTEA,
+ IN in_notify_s TEXT,
+ IN in_kyc_requirements TEXT,
+ IN in_requirement_row INT8,
OUT out_invalid_officer BOOLEAN,
OUT out_last_date INT8)
LANGUAGE plpgsql
@@ -30,7 +32,7 @@ AS $$
BEGIN
-- Check officer is eligible to make decisions.
PERFORM
- FROM exchange.aml_staff
+ FROM aml_staff
WHERE decider_pub=in_decider_pub
AND is_active
AND NOT read_only;
@@ -45,7 +47,7 @@ out_invalid_officer=FALSE;
-- Check no more recent decision exists.
SELECT decision_time
INTO out_last_date
- FROM exchange.aml_history
+ FROM aml_history
WHERE h_payto=in_h_payto
ORDER BY decision_time DESC;
IF FOUND
@@ -55,48 +57,71 @@ THEN
-- Refuse to insert older decision.
RETURN;
END IF;
- UPDATE exchange.aml_status
- SET threshold_val=in_new_threshold_val
- ,threshold_frac=in_new_threshold_frac
+ UPDATE aml_status
+ SET threshold=in_new_threshold
,status=in_new_status
+ ,kyc_requirement=in_requirement_row
WHERE h_payto=in_h_payto;
ASSERT FOUND, 'cannot have AML decision history but no AML status';
ELSE
out_last_date = 0;
- INSERT INTO exchange.aml_status
+ INSERT INTO aml_status
(h_payto
- ,threshold_val
- ,threshold_frac
- ,status)
+ ,threshold
+ ,status
+ ,kyc_requirement)
VALUES
(in_h_payto
- ,in_new_threshold_val
- ,in_new_threshold_frac
- ,in_new_status);
+ ,in_new_threshold
+ ,in_new_status
+ ,in_requirement_row)
+ ON CONFLICT (h_payto) DO
+ UPDATE SET
+ threshold=in_new_threshold
+ ,status=in_new_status;
END IF;
-INSERT INTO exchange.aml_history
+INSERT INTO aml_history
(h_payto
- ,new_threshold_val
- ,new_threshold_frac
+ ,new_threshold
,new_status
,decision_time
,justification
+ ,kyc_requirements
+ ,kyc_req_row
,decider_pub
,decider_sig
) VALUES
(in_h_payto
- ,in_new_threshold_val
- ,in_new_threshold_frac
+ ,in_new_threshold
,in_new_status
,in_decision_time
,in_justification
+ ,in_kyc_requirements
+ ,in_requirement_row
,in_decider_pub
,in_decider_sig);
+
+-- wake up taler-exchange-aggregator
+IF 0 = in_new_status
+THEN
+ INSERT INTO kyc_alerts
+ (h_payto
+ ,trigger_type)
+ VALUES
+ (in_h_payto,1);
+
+ EXECUTE FORMAT (
+ 'NOTIFY %s'
+ ,in_notify_s);
+
+END IF;
+
+
END $$;
-COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA)
+COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, taler_amount, INT4, INT8, TEXT, BYTEA, BYTEA, TEXT, TEXT, INT8)
IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table';
diff --git a/src/exchangedb/exchange_do_insert_aml_officer.sql b/src/exchangedb/exchange_do_insert_aml_officer.sql
index 5cb926c07..429ba11c7 100644
--- a/src/exchangedb/exchange_do_insert_aml_officer.sql
+++ b/src/exchangedb/exchange_do_insert_aml_officer.sql
@@ -17,7 +17,7 @@
CREATE OR REPLACE FUNCTION exchange_do_insert_aml_officer(
IN in_decider_pub BYTEA,
IN in_master_sig BYTEA,
- IN in_decider_name VARCHAR,
+ IN in_decider_name TEXT,
IN in_is_active BOOLEAN,
IN in_read_only BOOLEAN,
IN in_last_change INT8,
@@ -70,5 +70,5 @@ UPDATE exchange.aml_staff
END $$;
-COMMENT ON FUNCTION exchange_do_insert_aml_officer(BYTEA, BYTEA, VARCHAR, BOOL, BOOL, INT8)
+COMMENT ON FUNCTION exchange_do_insert_aml_officer(BYTEA, BYTEA, TEXT, BOOL, BOOL, INT8)
IS 'Inserts or updates AML staff record, making sure the update is more recent than the previous change';
diff --git a/src/exchangedb/exchange_do_insert_kyc_attributes.sql b/src/exchangedb/exchange_do_insert_kyc_attributes.sql
new file mode 100644
index 000000000..7db4d80c0
--- /dev/null
+++ b/src/exchangedb/exchange_do_insert_kyc_attributes.sql
@@ -0,0 +1,114 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+CREATE OR REPLACE FUNCTION exchange_do_insert_kyc_attributes(
+ IN in_process_row INT8,
+ IN in_h_payto BYTEA,
+ IN in_kyc_prox BYTEA,
+ IN in_provider_section TEXT,
+ IN in_satisfied_checks TEXT[],
+ IN in_birthday INT4,
+ IN in_provider_account_id TEXT,
+ IN in_provider_legitimization_id TEXT,
+ IN in_collection_time_ts INT8,
+ IN in_expiration_time INT8,
+ IN in_expiration_time_ts INT8,
+ IN in_enc_attributes BYTEA,
+ IN in_require_aml BOOLEAN,
+ IN in_kyc_completed_notify_s TEXT,
+ OUT out_ok BOOLEAN)
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ orig_reserve_pub BYTEA;
+ orig_reserve_found BOOLEAN;
+BEGIN
+
+INSERT INTO exchange.kyc_attributes
+ (h_payto
+ ,kyc_prox
+ ,provider
+ ,satisfied_checks
+ ,collection_time
+ ,expiration_time
+ ,encrypted_attributes
+ ,legitimization_serial
+ ) VALUES
+ (in_h_payto
+ ,in_kyc_prox
+ ,in_provider_section
+ ,in_satisfied_checks
+ ,in_collection_time_ts
+ ,in_expiration_time_ts
+ ,in_enc_attributes
+ ,in_process_row);
+
+UPDATE legitimization_processes
+ SET provider_user_id=in_provider_account_id
+ ,provider_legitimization_id=in_provider_legitimization_id
+ ,expiration_time=GREATEST(expiration_time,in_expiration_time)
+ ,finished=TRUE
+ WHERE h_payto=in_h_payto
+ AND legitimization_process_serial_id=in_process_row
+ AND provider_section=in_provider_section;
+out_ok = FOUND;
+
+
+-- If the h_payto refers to a reserve in the original requirements
+-- update the originating reserve's birthday.
+SELECT reserve_pub
+ INTO orig_reserve_pub
+ FROM exchange.legitimization_requirements
+ WHERE h_payto=in_h_payto
+ AND NOT reserve_pub IS NULL;
+orig_reserve_found = FOUND;
+
+IF orig_reserve_found
+THEN
+ UPDATE exchange.reserves
+ SET birthday=in_birthday
+ WHERE reserve_pub=orig_reserve_pub;
+END IF;
+
+IF in_require_aml
+THEN
+ INSERT INTO exchange.aml_status
+ (h_payto
+ ,status)
+ VALUES
+ (in_h_payto
+ ,1)
+ ON CONFLICT (h_payto) DO
+ UPDATE SET status=EXCLUDED.status | 1;
+END IF;
+
+EXECUTE FORMAT (
+ 'NOTIFY %s'
+ ,in_kyc_completed_notify_s);
+
+
+INSERT INTO kyc_alerts
+ (h_payto
+ ,trigger_type)
+ VALUES
+ (in_h_payto,1);
+
+
+END $$;
+
+
+COMMENT ON FUNCTION exchange_do_insert_kyc_attributes(INT8, BYTEA, BYTEA, TEXT, TEXT[], INT4, TEXT, TEXT, INT8, INT8, INT8, BYTEA, BOOL, TEXT)
+ IS 'Inserts new KYC attributes and updates the status of the legitimization process and the AML status for the account';
diff --git a/src/exchangedb/exchange_do_insert_or_update_policy_details.sql b/src/exchangedb/exchange_do_insert_or_update_policy_details.sql
index c7fe64d14..85e52d3d3 100644
--- a/src/exchangedb/exchange_do_insert_or_update_policy_details.sql
+++ b/src/exchangedb/exchange_do_insert_or_update_policy_details.sql
@@ -16,54 +16,42 @@
CREATE OR REPLACE FUNCTION exchange_do_insert_or_update_policy_details(
IN in_policy_hash_code BYTEA,
- IN in_policy_json VARCHAR,
+ IN in_policy_json TEXT,
IN in_deadline INT8,
- IN in_commitment_val INT8,
- IN in_commitment_frac INT4,
- IN in_accumulated_total_val INT8,
- IN in_accumulated_total_frac INT4,
- IN in_fee_val INT8,
- IN in_fee_frac INT4,
- IN in_transferable_val INT8,
- IN in_transferable_frac INT4,
+ IN in_commitment taler_amount,
+ IN in_accumulated_total taler_amount,
+ IN in_fee taler_amount,
+ IN in_transferable taler_amount,
IN in_fulfillment_state SMALLINT,
OUT out_policy_details_serial_id INT8,
- OUT out_accumulated_total_val INT8,
- OUT out_accumulated_total_frac INT4,
+ OUT out_accumulated_total taler_amount,
OUT out_fulfillment_state SMALLINT)
LANGUAGE plpgsql
AS $$
DECLARE
- cur_commitment_val INT8;
- cur_commitment_frac INT4;
- cur_accumulated_total_val INT8;
- cur_accumulated_total_frac INT4;
+ cur_commitment taler_amount;
+DECLARE
+ cur_accumulated_total taler_amount;
+DECLARE
+ rval RECORD;
BEGIN
-- First, try to create a new entry.
INSERT INTO policy_details
(policy_hash_code,
policy_json,
deadline,
- commitment_val,
- commitment_frac,
- accumulated_total_val,
- accumulated_total_frac,
- fee_val,
- fee_frac,
- transferable_val,
- transferable_frac,
+ commitment,
+ accumulated_total,
+ fee,
+ transferable,
fulfillment_state)
VALUES (in_policy_hash_code,
in_policy_json,
in_deadline,
- in_commitment_val,
- in_commitment_frac,
- in_accumulated_total_val,
- in_accumulated_total_frac,
- in_fee_val,
- in_fee_frac,
- in_transferable_val,
- in_transferable_frac,
+ in_commitment,
+ in_accumulated_total,
+ in_fee,
+ in_transferable,
in_fulfillment_state)
ON CONFLICT (policy_hash_code) DO NOTHING
RETURNING policy_details_serial_id INTO out_policy_details_serial_id;
@@ -71,34 +59,33 @@ BEGIN
-- If the insert was successful, return
-- We assume that the fullfilment_state was correct in first place.
IF FOUND THEN
- out_accumulated_total_val = in_accumulated_total_val;
- out_accumulated_total_frac = in_accumulated_total_frac;
- out_fulfillment_state = in_fulfillment_state;
+ out_accumulated_total = in_accumulated_total;
+ out_fulfillment_state = in_fulfillment_state;
RETURN;
END IF;
-- We had a conflict, grab the parts we need to update.
- SELECT policy_details_serial_id,
- commitment_val,
- commitment_frac,
- accumulated_total_val,
- accumulated_total_frac
- INTO out_policy_details_serial_id,
- cur_commitment_val,
- cur_commitment_frac,
- cur_accumulated_total_val,
- cur_accumulated_total_frac
+ SELECT policy_details_serial_id
+ ,commitment
+ ,accumulated_total
+ INTO rval
FROM policy_details
WHERE policy_hash_code = in_policy_hash_code;
+ -- We use rval as workaround as we cannot select
+ -- directly into the amount due to Postgres limitations.
+ out_policy_details_serial_id := rval.policy_details_serial_id;
+ cur_commitment := rval.commitment;
+ cur_accumulated_total := rval.accumulated_total;
+
-- calculate the new values (overflows throws exception)
- out_accumulated_total_val = cur_accumulated_total_val + in_accumulated_total_val;
- out_accumulated_total_frac = cur_accumulated_total_frac + in_accumulated_total_frac;
+ out_accumulated_total.val = cur_accumulated_total.val + in_accumulated_total.val;
+ out_accumulated_total.frac = cur_accumulated_total.frac + in_accumulated_total.frac;
-- normalize
- out_accumulated_total_val = out_accumulated_total_val + out_accumulated_total_frac / 100000000;
- out_accumulated_total_frac = out_accumulated_total_frac % 100000000;
+ out_accumulated_total.val = out_accumulated_total.val + out_accumulated_total.frac / 100000000;
+ out_accumulated_total.frac = out_accumulated_total.frac % 100000000;
- IF (out_accumulated_total_val > (1 << 52))
+ IF (out_accumulated_total.val > (1 << 52))
THEN
RAISE EXCEPTION 'accumulation overflow';
END IF;
@@ -106,22 +93,21 @@ BEGIN
-- Set the fulfillment_state according to the values.
-- For now, we only update the state when it was INSUFFICIENT.
- -- FIXME: What to do in case of Failure or other state?
- IF (out_fullfillment_state = 1) -- INSUFFICIENT
+ -- FIXME[oec] #7999: What to do in case of Failure or other state?
+ IF (out_fullfillment_state = 2) -- INSUFFICIENT
THEN
- IF (out_accumulated_total_val >= cur_commitment_val OR
- (out_accumulated_total_val = cur_commitment_val AND
- out_accumulated_total_frac >= cur_commitment_frac))
+ IF (out_accumulated_total.val >= cur_commitment.val OR
+ (out_accumulated_total.val = cur_commitment.val AND
+ out_accumulated_total.frac >= cur_commitment.frac))
THEN
- out_fulfillment_state = 2; -- READY
+ out_fulfillment_state = 3; -- READY
END IF;
END IF;
-- Now, update the record
UPDATE exchange.policy_details
SET
- accumulated_val = out_accumulated_total_val,
- accumulated_frac = out_accumulated_total_frac,
+ accumulated = out_accumulated_total,
fulfillment_state = out_fulfillment_state
WHERE
policy_details_serial_id = out_policy_details_serial_id;
diff --git a/src/exchangedb/exchange_do_melt.sql b/src/exchangedb/exchange_do_melt.sql
index c0290b561..0200986fa 100644
--- a/src/exchangedb/exchange_do_melt.sql
+++ b/src/exchangedb/exchange_do_melt.sql
@@ -19,8 +19,7 @@
CREATE OR REPLACE FUNCTION exchange_do_melt(
IN in_cs_rms BYTEA,
- IN in_amount_with_fee_val INT8,
- IN in_amount_with_fee_frac INT4,
+ IN in_amount_with_fee taler_amount,
IN in_rc BYTEA,
IN in_old_coin_pub BYTEA,
IN in_old_coin_sig BYTEA,
@@ -45,16 +44,14 @@ INSERT INTO exchange.refresh_commitments
(rc
,old_coin_pub
,old_coin_sig
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,amount_with_fee
,noreveal_index
)
VALUES
(in_rc
,in_old_coin_pub
,in_old_coin_sig
- ,in_amount_with_fee_val
- ,in_amount_with_fee_frac
+ ,in_amount_with_fee
,in_noreveal_index)
ON CONFLICT DO NOTHING;
@@ -84,13 +81,13 @@ THEN
-- operations, and then see if any of these
-- reveal operations was involved in a recoup.
PERFORM
- FROM exchange.recoup_refresh
+ FROM recoup_refresh
WHERE rrc_serial IN
(SELECT rrc_serial
- FROM exchange.refresh_revealed_coins
+ FROM refresh_revealed_coins
WHERE melt_serial_id IN
(SELECT melt_serial_id
- FROM exchange.refresh_commitments
+ FROM refresh_commitments
WHERE old_coin_pub=in_old_coin_pub));
IF NOT FOUND
THEN
@@ -104,24 +101,24 @@ out_zombie_bad=FALSE; -- zombie is OK
-- Check and update balance of the coin.
-UPDATE known_coins
+UPDATE known_coins kc
SET
- remaining_frac=remaining_frac-in_amount_with_fee_frac
+ remaining.frac=(kc.remaining).frac-in_amount_with_fee.frac
+ CASE
- WHEN remaining_frac < in_amount_with_fee_frac
+ WHEN (kc.remaining).frac < in_amount_with_fee.frac
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val-in_amount_with_fee_val
+ remaining.val=(kc.remaining).val-in_amount_with_fee.val
- CASE
- WHEN remaining_frac < in_amount_with_fee_frac
+ WHEN (kc.remaining).frac < in_amount_with_fee.frac
THEN 1
ELSE 0
END
WHERE coin_pub=in_old_coin_pub
- AND ( (remaining_val > in_amount_with_fee_val) OR
- ( (remaining_frac >= in_amount_with_fee_frac) AND
- (remaining_val >= in_amount_with_fee_val) ) );
+ AND ( ((kc.remaining).val > in_amount_with_fee.val) OR
+ ( ((kc.remaining).frac >= in_amount_with_fee.frac) AND
+ ((kc.remaining).val >= in_amount_with_fee.val) ) );
IF NOT FOUND
THEN
@@ -183,4 +180,3 @@ out_balance_ok=TRUE;
out_noreveal_index=in_noreveal_index;
END $$;
-
diff --git a/src/exchangedb/exchange_do_purse_delete.sql b/src/exchangedb/exchange_do_purse_delete.sql
index 096475b43..5668f7bec 100644
--- a/src/exchangedb/exchange_do_purse_delete.sql
+++ b/src/exchangedb/exchange_do_purse_delete.sql
@@ -91,21 +91,20 @@ END IF;
-- restore balance to each coin deposited into the purse
FOR my_deposit IN
SELECT coin_pub
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,amount_with_fee
FROM exchange.purse_deposits
WHERE purse_pub = in_purse_pub
LOOP
- UPDATE exchange.known_coins SET
- remaining_frac=remaining_frac+my_deposit.amount_with_fee_frac
+ UPDATE known_coins kc SET
+ remaining.frac=(kc.remaining).frac+(my_deposit.amount_with_fee).frac
- CASE
- WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000
+ WHEN (kc.remaining).frac+(my_deposit.amount_with_fee).frac >= 100000000
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val+my_deposit.amount_with_fee_val
+ remaining.val=(kc.remaining).val+(my_deposit.amount_with_fee).val
+ CASE
- WHEN remaining_frac+my_deposit.amount_with_fee_frac >= 100000000
+ WHEN (kc.remaining).frac+(my_deposit.amount_with_fee).frac >= 100000000
THEN 1
ELSE 0
END
diff --git a/src/exchangedb/exchange_do_purse_deposit.sql b/src/exchangedb/exchange_do_purse_deposit.sql
index 62fcb3b12..49d3c919b 100644
--- a/src/exchangedb/exchange_do_purse_deposit.sql
+++ b/src/exchangedb/exchange_do_purse_deposit.sql
@@ -17,12 +17,10 @@
CREATE OR REPLACE FUNCTION exchange_do_purse_deposit(
IN in_partner_id INT8,
IN in_purse_pub BYTEA,
- IN in_amount_with_fee_val INT8,
- IN in_amount_with_fee_frac INT4,
+ IN in_amount_with_fee taler_amount,
IN in_coin_pub BYTEA,
IN in_coin_sig BYTEA,
- IN in_amount_without_fee_val INT8,
- IN in_amount_without_fee_frac INT4,
+ IN in_amount_without_fee taler_amount,
IN in_reserve_expiration INT8,
IN in_now INT8,
OUT out_balance_ok BOOLEAN,
@@ -35,31 +33,29 @@ DECLARE
DECLARE
psi INT8; -- partner's serial ID (set if merged)
DECLARE
- my_amount_val INT8; -- total in purse
-DECLARE
- my_amount_frac INT4; -- total in purse
+ my_amount taler_amount; -- total in purse
DECLARE
was_paid BOOLEAN;
DECLARE
my_in_reserve_quota BOOLEAN;
DECLARE
my_reserve_pub BYTEA;
+DECLARE
+ rval RECORD;
BEGIN
-- Store the deposit request.
-INSERT INTO exchange.purse_deposits
+INSERT INTO purse_deposits
(partner_serial_id
,purse_pub
,coin_pub
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,amount_with_fee
,coin_sig)
VALUES
(in_partner_id
,in_purse_pub
,in_coin_pub
- ,in_amount_with_fee_val
- ,in_amount_with_fee_frac
+ ,in_amount_with_fee
,in_coin_sig)
ON CONFLICT DO NOTHING;
@@ -67,11 +63,12 @@ IF NOT FOUND
THEN
-- Idempotency check: check if coin_sig is the same,
-- if so, success, otherwise conflict!
+
PERFORM
- FROM exchange.purse_deposits
- WHERE coin_pub = in_coin_pub
- AND purse_pub = in_purse_pub
- AND coin_sig = in_cion_sig;
+ FROM purse_deposits
+ WHERE purse_pub = in_purse_pub
+ AND coin_pub = in_coin_pub
+ AND coin_sig = in_coin_sig;
IF NOT FOUND
THEN
-- Deposit exists, but with differences. Not allowed.
@@ -79,6 +76,12 @@ THEN
out_late=FALSE;
out_conflict=TRUE;
RETURN;
+ ELSE
+ -- Deposit exists, do not count for balance. Allow.
+ out_late=FALSE;
+ out_balance_ok=TRUE;
+ out_conflict=FALSE;
+ RETURN;
END IF;
END IF;
@@ -98,24 +101,24 @@ END IF;
-- Debit the coin
-- Check and update balance of the coin.
-UPDATE known_coins
+UPDATE known_coins kc
SET
- remaining_frac=remaining_frac-in_amount_with_fee_frac
+ remaining.frac=(kc.remaining).frac-in_amount_with_fee.frac
+ CASE
- WHEN remaining_frac < in_amount_with_fee_frac
+ WHEN (kc.remaining).frac < in_amount_with_fee.frac
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val-in_amount_with_fee_val
+ remaining.val=(kc.remaining).val-in_amount_with_fee.val
- CASE
- WHEN remaining_frac < in_amount_with_fee_frac
+ WHEN (kc.remaining).frac < in_amount_with_fee.frac
THEN 1
ELSE 0
END
WHERE coin_pub=in_coin_pub
- AND ( (remaining_val > in_amount_with_fee_val) OR
- ( (remaining_frac >= in_amount_with_fee_frac) AND
- (remaining_val >= in_amount_with_fee_val) ) );
+ AND ( ((kc.remaining).val > in_amount_with_fee.val) OR
+ ( ((kc.remaining).frac >= in_amount_with_fee.frac) AND
+ ((kc.remaining).val >= in_amount_with_fee.val) ) );
IF NOT FOUND
THEN
@@ -128,17 +131,17 @@ END IF;
-- Credit the purse.
-UPDATE purse_requests
+UPDATE purse_requests pr
SET
- balance_frac=balance_frac+in_amount_without_fee_frac
+ balance.frac=(pr.balance).frac+in_amount_without_fee.frac
- CASE
- WHEN balance_frac+in_amount_without_fee_frac >= 100000000
+ WHEN (pr.balance).frac+in_amount_without_fee.frac >= 100000000
THEN 100000000
ELSE 0
END,
- balance_val=balance_val+in_amount_without_fee_val
+ balance.val=(pr.balance).val+in_amount_without_fee.val
+ CASE
- WHEN balance_frac+in_amount_without_fee_frac >= 100000000
+ WHEN (pr.balance).frac+in_amount_without_fee.frac >= 100000000
THEN 1
ELSE 0
END
@@ -152,7 +155,7 @@ SELECT COALESCE(partner_serial_id,0)
,reserve_pub
INTO psi
,my_reserve_pub
- FROM exchange.purse_merges
+ FROM purse_merges
WHERE purse_pub=in_purse_pub;
IF NOT FOUND
@@ -163,24 +166,26 @@ THEN
END IF;
SELECT
- amount_with_fee_val
- ,amount_with_fee_frac
+ amount_with_fee
,in_reserve_quota
INTO
- my_amount_val
- ,my_amount_frac
- ,my_in_reserve_quota
- FROM exchange.purse_requests
+ rval
+ FROM exchange.purse_requests preq
WHERE (purse_pub=in_purse_pub)
- AND ( ( ( (amount_with_fee_val <= balance_val)
- AND (amount_with_fee_frac <= balance_frac) )
- OR (amount_with_fee_val < balance_val) ) );
+ AND ( ( ( ((preq.amount_with_fee).val <= (preq.balance).val)
+ AND ((preq.amount_with_fee).frac <= (preq.balance).frac) )
+ OR ((preq.amount_with_fee).val < (preq.balance).val) ) );
IF NOT FOUND
THEN
out_late=FALSE;
RETURN;
END IF;
+-- We use rval as workaround as we cannot select
+-- directly into the amount due to Postgres limitations.
+my_amount := rval.amount_with_fee;
+my_in_reserve_quota := rval.in_reserve_quota;
+
-- Remember how this purse was finished.
INSERT INTO purse_decision
(purse_pub
@@ -207,7 +212,7 @@ THEN
SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
- FROM exchange.purse_merges
+ FROM purse_merges
WHERE purse_pub=my_purse_pub
LIMIT 1);
END IF;
@@ -224,14 +229,12 @@ ELSE
-- This is a local reserve, update balance immediately.
INSERT INTO reserves
(reserve_pub
- ,current_balance_frac
- ,current_balance_val
+ ,current_balance
,expiration_date
,gc_date)
VALUES
(my_reserve_pub
- ,my_amount_frac
- ,my_amount_val
+ ,my_amount
,in_reserve_expiration
,in_reserve_expiration)
ON CONFLICT DO NOTHING;
@@ -241,15 +244,15 @@ ELSE
-- Reserve existed, thus UPDATE instead of INSERT.
UPDATE reserves
SET
- current_balance_frac=current_balance_frac+my_amount_frac
+ current_balance.frac=(current_balance).frac+my_amount.frac
- CASE
- WHEN current_balance_frac + my_amount_frac >= 100000000
+ WHEN (current_balance).frac + my_amount.frac >= 100000000
THEN 100000000
ELSE 0
END
- ,current_balance_val=current_balance_val+my_amount_val
+ ,current_balance.val=(current_balance).val+my_amount.val
+ CASE
- WHEN current_balance_frac + my_amount_frac >= 100000000
+ WHEN (current_balance).frac + my_amount.frac >= 100000000
THEN 1
ELSE 0
END
diff --git a/src/exchangedb/exchange_do_purse_merge.sql b/src/exchangedb/exchange_do_purse_merge.sql
index f02dd5dcd..946fd7e97 100644
--- a/src/exchangedb/exchange_do_purse_merge.sql
+++ b/src/exchangedb/exchange_do_purse_merge.sql
@@ -19,7 +19,7 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_merge(
IN in_merge_sig BYTEA,
IN in_merge_timestamp INT8,
IN in_reserve_sig BYTEA,
- IN in_partner_url VARCHAR,
+ IN in_partner_url TEXT,
IN in_reserve_pub BYTEA,
IN in_wallet_h_payto BYTEA,
IN in_expiration_date INT8,
@@ -29,19 +29,32 @@ CREATE OR REPLACE FUNCTION exchange_do_purse_merge(
LANGUAGE plpgsql
AS $$
DECLARE
- my_amount_val INT8;
+ my_amount taler_amount;
DECLARE
- my_amount_frac INT4;
-DECLARE
- my_purse_fee_val INT8;
-DECLARE
- my_purse_fee_frac INT4;
+ my_purse_fee taler_amount;
DECLARE
my_partner_serial_id INT8;
DECLARE
my_in_reserve_quota BOOLEAN;
+DECLARE
+ rval RECORD;
+DECLARE
+ reserve RECORD;
+DECLARE
+ balance taler_amount;
BEGIN
+-- Initialize reserve, if not yet exists.
+INSERT INTO reserves
+ (reserve_pub
+ ,expiration_date
+ ,gc_date)
+ VALUES
+ (in_reserve_pub
+ ,in_expiration_date
+ ,in_expiration_date)
+ ON CONFLICT DO NOTHING;
+
IF in_partner_url IS NULL
THEN
@@ -65,33 +78,33 @@ END IF;
out_no_partner=FALSE;
-
-- Check purse is 'full'.
-SELECT amount_with_fee_val
- ,amount_with_fee_frac
- ,purse_fee_val
- ,purse_fee_frac
+SELECT amount_with_fee
+ ,purse_fee
,in_reserve_quota
- INTO my_amount_val
- ,my_amount_frac
- ,my_purse_fee_val
- ,my_purse_fee_frac
- ,my_in_reserve_quota
- FROM exchange.purse_requests
+ INTO rval
+ FROM purse_requests pr
WHERE purse_pub=in_purse_pub
- AND balance_val >= amount_with_fee_val
- AND ( (balance_frac >= amount_with_fee_frac) OR
- (balance_val > amount_with_fee_val) );
+ AND (pr.balance).val >= (pr.amount_with_fee).val
+ AND ( (pr.balance).frac >= (pr.amount_with_fee).frac OR
+ (pr.balance).val > (pr.amount_with_fee).val );
IF NOT FOUND
THEN
out_no_balance=TRUE;
out_conflict=FALSE;
RETURN;
END IF;
+
+-- We use rval as workaround as we cannot select
+-- directly into the amount due to Postgres limitations.
+my_amount := rval.amount_with_fee;
+my_purse_fee := rval.purse_fee;
+my_in_reserve_quota := rval.in_reserve_quota;
+
out_no_balance=FALSE;
-- Store purse merge signature, checks for purse_pub uniqueness
-INSERT INTO exchange.purse_merges
+INSERT INTO purse_merges
(partner_serial_id
,reserve_pub
,purse_pub
@@ -111,7 +124,7 @@ THEN
-- Note that by checking 'merge_sig', we implicitly check
-- identity over everything that the signature covers.
PERFORM
- FROM exchange.purse_merges
+ FROM purse_merges
WHERE purse_pub=in_purse_pub
AND merge_sig=in_merge_sig;
IF NOT FOUND
@@ -149,17 +162,6 @@ END IF;
out_conflict=FALSE;
--- Initialize reserve, if not yet exists.
-INSERT INTO reserves
- (reserve_pub
- ,expiration_date
- ,gc_date)
- VALUES
- (in_reserve_pub
- ,in_expiration_date
- ,in_expiration_date)
- ON CONFLICT DO NOTHING;
-
IF (my_in_reserve_quota)
THEN
@@ -167,13 +169,13 @@ THEN
SET purses_active=purses_active-1
WHERE reserve_pub IN
(SELECT reserve_pub
- FROM exchange.purse_merges
+ FROM purse_merges
WHERE purse_pub=my_purse_pub
LIMIT 1);
END IF;
-- Store account merge signature.
-INSERT INTO exchange.account_merges
+INSERT INTO account_merges
(reserve_pub
,reserve_sig
,purse_pub
@@ -196,26 +198,33 @@ ELSE
-- This is a local reserve, update reserve balance immediately.
-- Refund the purse fee, by adding it to the purse value:
- my_amount_val = my_amount_val + my_purse_fee_val;
- my_amount_frac = my_amount_frac + my_purse_fee_frac;
+ my_amount.val = my_amount.val + my_purse_fee.val;
+ my_amount.frac = my_amount.frac + my_purse_fee.frac;
-- normalize result
- my_amount_val = my_amount_val + my_amount_frac / 100000000;
- my_amount_frac = my_amount_frac % 100000000;
+ my_amount.val = my_amount.val + my_amount.frac / 100000000;
+ my_amount.frac = my_amount.frac % 100000000;
+
+ SELECT *
+ INTO reserve
+ FROM exchange.reserves
+ WHERE reserve_pub=in_reserve_pub;
+
+ balance = reserve.current_balance;
+ balance.frac=balance.frac+my_amount.frac
+ - CASE
+ WHEN balance.frac + my_amount.frac >= 100000000
+ THEN 100000000
+ ELSE 0
+ END;
+ balance.val=balance.val+my_amount.val
+ + CASE
+ WHEN balance.frac + my_amount.frac >= 100000000
+ THEN 1
+ ELSE 0
+ END;
UPDATE exchange.reserves
- SET
- current_balance_frac=current_balance_frac+my_amount_frac
- - CASE
- WHEN current_balance_frac + my_amount_frac >= 100000000
- THEN 100000000
- ELSE 0
- END,
- current_balance_val=current_balance_val+my_amount_val
- + CASE
- WHEN current_balance_frac + my_amount_frac >= 100000000
- THEN 1
- ELSE 0
- END
+ SET current_balance=balance
WHERE reserve_pub=in_reserve_pub;
END IF;
@@ -224,6 +233,5 @@ RETURN;
END $$;
-COMMENT ON FUNCTION exchange_do_purse_merge(BYTEA, BYTEA, INT8, BYTEA, VARCHAR, BYTEA, BYTEA, INT8)
+COMMENT ON FUNCTION exchange_do_purse_merge(BYTEA, BYTEA, INT8, BYTEA, TEXT, BYTEA, BYTEA, INT8)
IS 'Checks that the partner exists, the purse has not been merged with a different reserve and that the purse is full. If so, persists the merge data and either merges the purse with the reserve or marks it as ready for the taler-exchange-router. Caller MUST abort the transaction on failures so as to not persist data by accident.';
-
diff --git a/src/exchangedb/exchange_do_recoup_by_reserve.sql b/src/exchangedb/exchange_do_recoup_by_reserve.sql
index 6a7ea725e..80f953c4a 100644
--- a/src/exchangedb/exchange_do_recoup_by_reserve.sql
+++ b/src/exchangedb/exchange_do_recoup_by_reserve.sql
@@ -25,8 +25,7 @@ RETURNS TABLE
coin_pub BYTEA,
coin_sig BYTEA,
coin_blind BYTEA,
- amount_val BIGINT,
- amount_frac INTEGER,
+ amount taler_amount,
recoup_timestamp BIGINT
)
LANGUAGE plpgsql
@@ -37,22 +36,25 @@ DECLARE
c_pub BYTEA;
BEGIN
SELECT reserve_uuid
- INTO res_uuid
- FROM exchange.reserves
- WHERE reserves.reserve_pub = res_pub;
+ INTO res_uuid
+ FROM reserves
+ WHERE reserve_pub = res_pub;
FOR blind_ev IN
SELECT h_blind_ev
- FROM exchange.reserves_out_by_reserve
- WHERE reserves_out_by_reserve.reserve_uuid = res_uuid
+ FROM reserves_out ro
+ JOIN reserve_history rh
+ ON (rh.serial_id = ro.reserve_out_serial_id)
+ WHERE rh.reserve_pub = res_pub
+ AND rh.table_name='reserves_out'
LOOP
SELECT robr.coin_pub
INTO c_pub
FROM exchange.recoup_by_reserve robr
WHERE robr.reserve_out_serial_id = (
- SELECT reserves_out.reserve_out_serial_id
- FROM exchange.reserves_out
- WHERE reserves_out.h_blind_ev = blind_ev
+ SELECT reserve_out_serial_id
+ FROM reserves_out
+ WHERE h_blind_ev = blind_ev
);
RETURN QUERY
SELECT kc.denom_sig,
@@ -60,16 +62,20 @@ BEGIN
rc.coin_pub,
rc.coin_sig,
rc.coin_blind,
- rc.amount_val,
- rc.amount_frac,
+ rc.amount,
rc.recoup_timestamp
FROM (
- SELECT *
+ SELECT denom_sig
+ ,denominations_serial
FROM exchange.known_coins
WHERE known_coins.coin_pub = c_pub
) kc
JOIN (
- SELECT *
+ SELECT coin_pub
+ ,coin_sig
+ ,coin_blind
+ ,amount
+ ,recoup_timestamp
FROM exchange.recoup
WHERE recoup.coin_pub = c_pub
) rc USING (coin_pub);
@@ -79,4 +85,3 @@ $$;
COMMENT ON FUNCTION exchange_do_recoup_by_reserve
IS 'Recoup by reserve as a function to make sure we hit only the needed partition and not all when joining as joins on distributed tables fetch ALL rows from the shards';
-
diff --git a/src/exchangedb/exchange_do_recoup_to_coin.sql b/src/exchangedb/exchange_do_recoup_to_coin.sql
index 5598ec20c..6cecfb7f8 100644
--- a/src/exchangedb/exchange_do_recoup_to_coin.sql
+++ b/src/exchangedb/exchange_do_recoup_to_coin.sql
@@ -31,9 +31,9 @@ CREATE OR REPLACE FUNCTION exchange_do_recoup_to_coin(
LANGUAGE plpgsql
AS $$
DECLARE
- tmp_val INT8; -- amount recouped
+ rval RECORD;
DECLARE
- tmp_frac INT8; -- amount recouped
+ tmp taler_amount; -- amount recouped
BEGIN
-- Shards: UPDATE known_coins (by coin_pub)
@@ -41,17 +41,13 @@ BEGIN
-- UPDATE known_coins (by coin_pub)
-- INSERT recoup_refresh (by coin_pub)
-
out_internal_failure=FALSE;
-
-- Check remaining balance of the coin.
SELECT
- remaining_frac
- ,remaining_val
+ remaining
INTO
- tmp_frac
- ,tmp_val
+ rval
FROM exchange.known_coins
WHERE coin_pub=in_coin_pub;
@@ -62,14 +58,16 @@ THEN
RETURN;
END IF;
-IF tmp_val + tmp_frac = 0
+tmp := rval.remaining;
+
+IF tmp.val + tmp.frac = 0
THEN
-- Check for idempotency
SELECT
recoup_timestamp
INTO
out_recoup_timestamp
- FROM exchange.recoup_refresh
+ FROM recoup_refresh
WHERE coin_pub=in_coin_pub;
out_recoup_ok=FOUND;
RETURN;
@@ -78,29 +76,27 @@ END IF;
-- Update balance of the coin.
UPDATE known_coins
SET
- remaining_frac=0
- ,remaining_val=0
+ remaining.val = 0
+ ,remaining.frac = 0
WHERE coin_pub=in_coin_pub;
-
-- Credit the old coin.
-UPDATE known_coins
+UPDATE known_coins kc
SET
- remaining_frac=remaining_frac+tmp_frac
+ remaining.frac=(kc.remaining).frac+tmp.frac
- CASE
- WHEN remaining_frac+tmp_frac >= 100000000
+ WHEN (kc.remaining).frac+tmp.frac >= 100000000
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val+tmp_val
+ remaining.val=(kc.remaining).val+tmp.val
+ CASE
- WHEN remaining_frac+tmp_frac >= 100000000
+ WHEN (kc.remaining).frac+tmp.frac >= 100000000
THEN 1
ELSE 0
END
WHERE coin_pub=in_old_coin_pub;
-
IF NOT FOUND
THEN
RAISE NOTICE 'failed to increase old coin balance from recoup';
@@ -110,13 +106,12 @@ THEN
END IF;
-INSERT INTO exchange.recoup_refresh
+INSERT INTO recoup_refresh
(coin_pub
,known_coin_id
,coin_sig
,coin_blind
- ,amount_val
- ,amount_frac
+ ,amount
,recoup_timestamp
,rrc_serial
)
@@ -125,8 +120,7 @@ VALUES
,in_known_coin_id
,in_coin_sig
,in_coin_blind
- ,tmp_val
- ,tmp_frac
+ ,tmp
,in_recoup_timestamp
,in_rrc_serial);
@@ -139,4 +133,3 @@ END $$;
-- COMMENT ON FUNCTION exchange_do_recoup_to_coin(INT8, INT4, BYTEA, BOOLEAN, BOOLEAN)
-- IS 'Executes a recoup-refresh of a coin that was obtained from a refresh-reveal process';
-
diff --git a/src/exchangedb/exchange_do_recoup_to_reserve.sql b/src/exchangedb/exchange_do_recoup_to_reserve.sql
index 39baba8fa..10ae063bd 100644
--- a/src/exchangedb/exchange_do_recoup_to_reserve.sql
+++ b/src/exchangedb/exchange_do_recoup_to_reserve.sql
@@ -31,9 +31,11 @@ CREATE OR REPLACE FUNCTION exchange_do_recoup_to_reserve(
LANGUAGE plpgsql
AS $$
DECLARE
- tmp_val INT8; -- amount recouped
-DECLARE
- tmp_frac INT8; -- amount recouped
+ tmp taler_amount; -- amount recouped
+ balance taler_amount; -- current balance of the reserve
+ new_balance taler_amount; -- new balance of the reserve
+ reserve RECORD;
+ rval RECORD;
BEGIN
-- Shards: SELECT known_coins (by coin_pub)
-- SELECT recoup (by coin_pub)
@@ -46,11 +48,9 @@ out_internal_failure=FALSE;
-- Check remaining balance of the coin.
SELECT
- remaining_frac
- ,remaining_val
+ remaining
INTO
- tmp_frac
- ,tmp_val
+ rval
FROM exchange.known_coins
WHERE coin_pub=in_coin_pub;
@@ -61,7 +61,9 @@ THEN
RETURN;
END IF;
-IF tmp_val + tmp_frac = 0
+tmp := rval.remaining;
+
+IF tmp.val + tmp.frac = 0
THEN
-- Check for idempotency
SELECT
@@ -79,26 +81,35 @@ END IF;
-- Update balance of the coin.
UPDATE known_coins
SET
- remaining_frac=0
- ,remaining_val=0
+ remaining.val = 0
+ ,remaining.frac = 0
WHERE coin_pub=in_coin_pub;
+-- Get current balance
+SELECT current_balance
+ INTO reserve
+ FROM reserves
+ WHERE reserve_pub=in_reserve_pub;
+
+balance = reserve.current_balance;
+new_balance.frac=balance.frac+tmp.frac
+ - CASE
+ WHEN balance.frac+tmp.frac >= 100000000
+ THEN 100000000
+ ELSE 0
+ END;
+
+new_balance.val=balance.val+tmp.val
+ + CASE
+ WHEN balance.frac+tmp.frac >= 100000000
+ THEN 1
+ ELSE 0
+ END;
-- Credit the reserve and update reserve timers.
UPDATE reserves
SET
- current_balance_frac=current_balance_frac+tmp_frac
- - CASE
- WHEN current_balance_frac+tmp_frac >= 100000000
- THEN 100000000
- ELSE 0
- END,
- current_balance_val=current_balance_val+tmp_val
- + CASE
- WHEN current_balance_frac+tmp_frac >= 100000000
- THEN 1
- ELSE 0
- END,
+ current_balance = new_balance,
gc_date=GREATEST(gc_date, in_reserve_gc),
expiration_date=GREATEST(expiration_date, in_reserve_expiration)
WHERE reserve_pub=in_reserve_pub;
@@ -117,8 +128,7 @@ INSERT INTO exchange.recoup
(coin_pub
,coin_sig
,coin_blind
- ,amount_val
- ,amount_frac
+ ,amount
,recoup_timestamp
,reserve_out_serial_id
)
@@ -126,8 +136,7 @@ VALUES
(in_coin_pub
,in_coin_sig
,in_coin_blind
- ,tmp_val
- ,tmp_frac
+ ,tmp
,in_recoup_timestamp
,in_reserve_out_serial_id);
@@ -139,6 +148,3 @@ END $$;
-- COMMENT ON FUNCTION exchange_do_recoup_to_reserve(INT8, INT4, BYTEA, BOOLEAN, BOOLEAN)
-- IS 'Executes a recoup of a coin that was withdrawn from a reserve';
-
-
-
diff --git a/src/exchangedb/exchange_do_refund.sql b/src/exchangedb/exchange_do_refund.sql
index ceaabfe16..a95746127 100644
--- a/src/exchangedb/exchange_do_refund.sql
+++ b/src/exchangedb/exchange_do_refund.sql
@@ -1,6 +1,6 @@
--
-- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
+-- Copyright (C) 2014--2023 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
@@ -15,12 +15,9 @@
--
CREATE OR REPLACE FUNCTION exchange_do_refund(
- IN in_amount_with_fee_val INT8,
- IN in_amount_with_fee_frac INT4,
- IN in_amount_val INT8,
- IN in_amount_frac INT4,
- IN in_deposit_fee_val INT8,
- IN in_deposit_fee_frac INT4,
+ IN in_amount_with_fee taler_amount,
+ IN in_amount taler_amount,
+ IN in_deposit_fee taler_amount,
IN in_h_contract_terms BYTEA,
IN in_rtransaction_id INT8,
IN in_deposit_shard INT8,
@@ -35,15 +32,15 @@ CREATE OR REPLACE FUNCTION exchange_do_refund(
LANGUAGE plpgsql
AS $$
DECLARE
- dsi INT8; -- ID of deposit being refunded
+ bdsi INT8; -- ID of deposit being refunded
DECLARE
tmp_val INT8; -- total amount refunded
DECLARE
- tmp_frac INT8; -- total amount refunded
+ tmp_frac INT8; -- total amount refunded, large fraction to deal with overflows!
DECLARE
- deposit_val INT8; -- amount that was originally deposited
+ tmp taler_amount; -- total amount refunded, normalized
DECLARE
- deposit_frac INT8; -- amount that was originally deposited
+ deposit taler_amount; -- amount that was originally deposited
BEGIN
-- Shards: SELECT deposits (coin_pub, shard, h_contract_terms, merchant_pub)
-- INSERT refunds (by coin_pub, rtransaction_id) ON CONFLICT DO NOTHING
@@ -51,17 +48,19 @@ BEGIN
-- UPDATE known_coins (by coin_pub)
SELECT
- deposit_serial_id
- ,amount_with_fee_val
- ,amount_with_fee_frac
- ,done
-INTO
- dsi
- ,deposit_val
- ,deposit_frac
+ bdep.batch_deposit_serial_id
+ ,(cdep.amount_with_fee).val
+ ,(cdep.amount_with_fee).frac
+ ,bdep.done
+ INTO
+ bdsi
+ ,deposit.val
+ ,deposit.frac
,out_gone
-FROM exchange.deposits
- WHERE coin_pub=in_coin_pub
+ FROM batch_deposits bdep
+ JOIN coin_deposits cdep
+ USING (batch_deposit_serial_id)
+ WHERE cdep.coin_pub=in_coin_pub
AND shard=in_deposit_shard
AND merchant_pub=in_merchant_pub
AND h_contract_terms=in_h_contract_terms;
@@ -76,21 +75,20 @@ THEN
RETURN;
END IF;
-INSERT INTO exchange.refunds
- (deposit_serial_id
+INSERT INTO refunds
+ (batch_deposit_serial_id
,coin_pub
,merchant_sig
,rtransaction_id
- ,amount_with_fee_val
- ,amount_with_fee_frac
+ ,amount_with_fee
)
VALUES
- (dsi
+ (bdsi
,in_coin_pub
,in_merchant_sig
,in_rtransaction_id
- ,in_amount_with_fee_val
- ,in_amount_with_fee_frac)
+ ,in_amount_with_fee
+ )
ON CONFLICT DO NOTHING;
IF NOT FOUND
@@ -103,10 +101,9 @@ THEN
PERFORM
FROM exchange.refunds
WHERE coin_pub=in_coin_pub
- AND deposit_serial_id=dsi
+ AND batch_deposit_serial_id=bdsi
AND rtransaction_id=in_rtransaction_id
- AND amount_with_fee_val=in_amount_with_fee_val
- AND amount_with_fee_frac=in_amount_with_fee_frac;
+ AND amount_with_fee=in_amount_with_fee;
IF NOT FOUND
THEN
@@ -136,14 +133,14 @@ END IF;
-- Check refund balance invariant.
SELECT
- SUM(amount_with_fee_val) -- overflow here is not plausible
- ,SUM(CAST(amount_with_fee_frac AS INT8)) -- compute using 64 bits
+ SUM((refs.amount_with_fee).val) -- overflow here is not plausible
+ ,SUM(CAST((refs.amount_with_fee).frac AS INT8)) -- compute using 64 bits
INTO
tmp_val
,tmp_frac
- FROM exchange.refunds
+ FROM refunds refs
WHERE coin_pub=in_coin_pub
- AND deposit_serial_id=dsi;
+ AND batch_deposit_serial_id=bdsi;
IF tmp_val IS NULL
THEN
RAISE NOTICE 'failed to sum up existing refunds';
@@ -154,15 +151,15 @@ THEN
END IF;
-- Normalize result before continuing
-tmp_val = tmp_val + tmp_frac / 100000000;
-tmp_frac = tmp_frac % 100000000;
+tmp.val = tmp_val + tmp_frac / 100000000;
+tmp.frac = tmp_frac % 100000000;
-- Actually check if the deposits are sufficient for the refund. Verbosely. ;-)
-IF (tmp_val < deposit_val)
+IF (tmp.val < deposit.val)
THEN
out_refund_ok=TRUE;
ELSE
- IF (tmp_val = deposit_val) AND (tmp_frac <= deposit_frac)
+ IF (tmp.val = deposit.val) AND (tmp.frac <= deposit.frac)
THEN
out_refund_ok=TRUE;
ELSE
@@ -170,42 +167,39 @@ ELSE
END IF;
END IF;
-IF (tmp_val = deposit_val) AND (tmp_frac = deposit_frac)
+IF (tmp.val = deposit.val) AND (tmp.frac = deposit.frac)
THEN
-- Refunds have reached the full value of the original
-- deposit. Also refund the deposit fee.
- in_amount_frac = in_amount_frac + in_deposit_fee_frac;
- in_amount_val = in_amount_val + in_deposit_fee_val;
+ in_amount.frac = in_amount.frac + in_deposit_fee.frac;
+ in_amount.val = in_amount.val + in_deposit_fee.val;
-- Normalize result before continuing
- in_amount_val = in_amount_val + in_amount_frac / 100000000;
- in_amount_frac = in_amount_frac % 100000000;
+ in_amount.val = in_amount.val + in_amount.frac / 100000000;
+ in_amount.frac = in_amount.frac % 100000000;
END IF;
-- Update balance of the coin.
-UPDATE known_coins
+UPDATE known_coins kc
SET
- remaining_frac=remaining_frac+in_amount_frac
+ remaining.frac=(kc.remaining).frac+in_amount.frac
- CASE
- WHEN remaining_frac+in_amount_frac >= 100000000
+ WHEN (kc.remaining).frac+in_amount.frac >= 100000000
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val+in_amount_val
+ remaining.val=(kc.remaining).val+in_amount.val
+ CASE
- WHEN remaining_frac+in_amount_frac >= 100000000
+ WHEN (kc.remaining).frac+in_amount.frac >= 100000000
THEN 1
ELSE 0
END
WHERE coin_pub=in_coin_pub;
-
out_conflict=FALSE;
out_not_found=FALSE;
END $$;
--- COMMENT ON FUNCTION exchange_do_refund(INT8, INT4, BYTEA, BOOLEAN, BOOLEAN)
--- IS 'Executes a refund operation, checking that the corresponding deposit was sufficient to cover the refunded amount';
-
-
+COMMENT ON FUNCTION exchange_do_refund(taler_amount, taler_amount, taler_amount, BYTEA, INT8, INT8, INT8, BYTEA, BYTEA, BYTEA)
+ IS 'Executes a refund operation, checking that the corresponding deposit was sufficient to cover the refunded amount';
diff --git a/src/exchangedb/exchange_do_refund_by_coin.sql b/src/exchangedb/exchange_do_refund_by_coin.sql
deleted file mode 100644
index ee00e2b5a..000000000
--- a/src/exchangedb/exchange_do_refund_by_coin.sql
+++ /dev/null
@@ -1,94 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-/*DROP FUNCTION exchange_do_refund_by_coin(
- IN in_coin_pub BYTEA,
- IN in_merchant_pub BYTEA,
- IN in_h_contract BYTEA
-);*/
-CREATE OR REPLACE FUNCTION exchange_do_refund_by_coin(
- IN in_coin_pub BYTEA,
- IN in_merchant_pub BYTEA,
- IN in_h_contract BYTEA
-)
-RETURNS SETOF record
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs CURSOR
- FOR
- SELECT
- amount_with_fee_val
- ,amount_with_fee_frac
- ,deposit_serial_id
- FROM refunds
- WHERE coin_pub=in_coin_pub;
-DECLARE
- i RECORD;
-BEGIN
-OPEN curs;
-LOOP
- FETCH NEXT FROM curs INTO i;
- EXIT WHEN NOT FOUND;
- RETURN QUERY
- SELECT
- i.amount_with_fee_val
- ,i.amount_with_fee_frac
- FROM deposits
- WHERE
- coin_pub=in_coin_pub
- AND merchant_pub=in_merchant_pub
- AND h_contract_terms=in_h_contract
- AND i.deposit_serial_id = deposit_serial_id;
-END LOOP;
-CLOSE curs;
-END $$;
-
-/*RETURNS TABLE(amount_with_fee_val INT8, amount_with_fee_frac INT4)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- curs CURSOR
- FOR
- SELECT
- r.amount_with_fee_val
- ,r.amount_with_fee_frac
- ,r.deposit_serial_id
- FROM refunds r
- WHERE r.coin_pub=in_coin_pub;
-DECLARE
- i RECORD;
-BEGIN
-OPEN curs;
-LOOP
- FETCH NEXT FROM curs INTO i;
- IF FOUND
- THEN
- RETURN QUERY
- SELECT
- i.amount_with_fee_val
- ,i.amount_with_fee_frac
- FROM deposits
- WHERE
- merchant_pub=in_merchant_pub
- AND h_contract_terms=in_h_contract
- AND i.deposit_serial_id = deposit_serial_id;
- END IF;
- EXIT WHEN NOT FOUND;
-END LOOP;
-CLOSE curs;
-
-END $$;
-*/
diff --git a/src/exchangedb/exchange_do_reserve_open.sql b/src/exchangedb/exchange_do_reserve_open.sql
index 5e80f713f..dd7a578ee 100644
--- a/src/exchangedb/exchange_do_reserve_open.sql
+++ b/src/exchangedb/exchange_do_reserve_open.sql
@@ -16,80 +16,66 @@
CREATE OR REPLACE FUNCTION exchange_do_reserve_open(
IN in_reserve_pub BYTEA,
- IN in_total_paid_val INT8,
- IN in_total_paid_frac INT4,
- IN in_reserve_payment_val INT8,
- IN in_reserve_payment_frac INT4,
+ IN in_total_paid taler_amount,
+ IN in_reserve_payment taler_amount,
IN in_min_purse_limit INT4,
IN in_default_purse_limit INT4,
IN in_reserve_sig BYTEA,
IN in_desired_expiration INT8,
IN in_reserve_gc_delay INT8,
IN in_now INT8,
- IN in_open_fee_val INT8,
- IN in_open_fee_frac INT4,
- OUT out_open_cost_val INT8,
- OUT out_open_cost_frac INT4,
+ IN in_open_fee taler_amount,
+ OUT out_open_cost taler_amount,
OUT out_final_expiration INT8,
- OUT out_no_funds BOOLEAN)
+ OUT out_no_reserve BOOLEAN,
+ OUT out_no_funds BOOLEAN,
+ OUT out_reserve_balance taler_amount)
LANGUAGE plpgsql
AS $$
DECLARE
- my_balance_val INT8;
-DECLARE
- my_balance_frac INT4;
-DECLARE
- my_cost_val INT8;
-DECLARE
+ my_balance taler_amount;
+ my_cost taler_amount;
my_cost_tmp INT8;
-DECLARE
- my_cost_frac INT4;
-DECLARE
my_years_tmp INT4;
-DECLARE
my_years INT4;
-DECLARE
my_needs_update BOOL;
-DECLARE
- my_purses_allowed INT8;
-DECLARE
my_expiration_date INT8;
-DECLARE
- my_reserve_expiration INT8;
+ reserve RECORD;
BEGIN
--- FIXME: use SELECT FOR UPDATE?
-SELECT
- purses_allowed
- ,expiration_date
- ,current_balance_val
- ,current_balance_frac
-INTO
- my_purses_allowed
- ,my_reserve_expiration
- ,my_balance_val
- ,my_balance_frac
-FROM reserves
-WHERE
- reserve_pub=in_reserve_pub;
+SELECT current_balance
+ ,expiration_date
+ ,purses_allowed
+ INTO reserve
+ FROM reserves
+ WHERE reserve_pub=in_reserve_pub;
IF NOT FOUND
THEN
- -- FIXME: do we need to set a 'not found'?
RAISE NOTICE 'reserve not found';
+ out_no_reserve = TRUE;
+ out_no_funds = TRUE;
+ out_reserve_balance.val = 0;
+ out_reserve_balance.frac = 0;
+ out_open_cost.val = 0;
+ out_open_cost.frac = 0;
+ out_final_expiration = 0;
RETURN;
END IF;
+out_no_reserve = FALSE;
+out_reserve_balance = reserve.current_balance;
+
-- Do not allow expiration time to start in the past already
-IF (my_reserve_expiration < in_now)
+IF (reserve.expiration_date < in_now)
THEN
my_expiration_date = in_now;
ELSE
- my_expiration_date = my_reserve_expiration;
+ my_expiration_date = reserve.expiration_date;
END IF;
-my_cost_val = 0;
-my_cost_frac = 0;
+my_cost.val = 0;
+my_cost.frac = 0;
my_needs_update = FALSE;
my_years = 0;
@@ -97,62 +83,62 @@ my_years = 0;
IF (my_expiration_date < in_desired_expiration)
THEN
my_years = (31535999999999 + in_desired_expiration - my_expiration_date) / 31536000000000;
- my_purses_allowed = in_default_purse_limit;
+ reserve.purses_allowed = in_default_purse_limit;
my_expiration_date = my_expiration_date + 31536000000000 * my_years;
END IF;
-- Increase years based on purses requested
-IF (my_purses_allowed < in_min_purse_limit)
+IF (reserve.purses_allowed < in_min_purse_limit)
THEN
my_years = (31535999999999 + in_desired_expiration - in_now) / 31536000000000;
my_expiration_date = in_now + 31536000000000 * my_years;
- my_years_tmp = (in_min_purse_limit + in_default_purse_limit - my_purses_allowed - 1) / in_default_purse_limit;
+ my_years_tmp = (in_min_purse_limit + in_default_purse_limit - reserve.purses_allowed - 1) / in_default_purse_limit;
my_years = my_years + my_years_tmp;
- my_purses_allowed = my_purses_allowed + (in_default_purse_limit * my_years_tmp);
+ reserve.purses_allowed = reserve.purses_allowed + (in_default_purse_limit * my_years_tmp);
END IF;
-- Compute cost based on annual fees
IF (my_years > 0)
THEN
- my_cost_val = my_years * in_open_fee_val;
- my_cost_tmp = my_years * in_open_fee_frac / 100000000;
- IF (CAST (my_cost_val + my_cost_tmp AS INT8) < my_cost_val)
+ my_cost.val = my_years * in_open_fee.val;
+ my_cost_tmp = my_years * in_open_fee.frac / 100000000;
+ IF (CAST (my_cost.val + my_cost_tmp AS INT8) < my_cost.val)
THEN
- out_open_cost_val=9223372036854775807;
- out_open_cost_frac=2147483647;
+ out_open_cost.val=9223372036854775807;
+ out_open_cost.frac=2147483647;
out_final_expiration=my_expiration_date;
out_no_funds=FALSE;
RAISE NOTICE 'arithmetic issue computing amount';
RETURN;
END IF;
- my_cost_val = CAST (my_cost_val + my_cost_tmp AS INT8);
- my_cost_frac = my_years * in_open_fee_frac % 100000000;
+ my_cost.val = CAST (my_cost.val + my_cost_tmp AS INT8);
+ my_cost.frac = my_years * in_open_fee.frac % 100000000;
my_needs_update = TRUE;
END IF;
-- check if we actually have something to do
IF NOT my_needs_update
THEN
- out_final_expiration = my_reserve_expiration;
- out_open_cost_val = 0;
- out_open_cost_frac = 0;
+ out_final_expiration = reserve.expiration_date;
+ out_open_cost.val = 0;
+ out_open_cost.frac = 0;
out_no_funds=FALSE;
RAISE NOTICE 'no change required';
RETURN;
END IF;
-- Check payment (coins and reserve) would be sufficient.
-IF ( (in_total_paid_val < my_cost_val) OR
- ( (in_total_paid_val = my_cost_val) AND
- (in_total_paid_frac < my_cost_frac) ) )
+IF ( (in_total_paid.val < my_cost.val) OR
+ ( (in_total_paid.val = my_cost.val) AND
+ (in_total_paid.frac < my_cost.frac) ) )
THEN
- out_open_cost_val = my_cost_val;
- out_open_cost_frac = my_cost_frac;
+ out_open_cost.val = my_cost.val;
+ out_open_cost.frac = my_cost.frac;
out_no_funds=FALSE;
-- We must return a failure, which is indicated by
-- the expiration being below the desired expiration.
- IF (my_reserve_expiration >= in_desired_expiration)
+ IF (reserve.expiration_date >= in_desired_expiration)
THEN
-- This case is relevant especially if the purse
-- count was to be increased and the payment was
@@ -160,32 +146,32 @@ THEN
RAISE NOTICE 'forcing low expiration time';
out_final_expiration = 0;
ELSE
- out_final_expiration = my_reserve_expiration;
+ out_final_expiration = reserve.expiration_date;
END IF;
RAISE NOTICE 'amount paid too low';
RETURN;
END IF;
-- Check reserve balance is sufficient.
-IF (my_balance_val > in_reserve_payment_val)
+IF (out_reserve_balance.val > in_reserve_payment.val)
THEN
- IF (my_balance_frac >= in_reserve_payment_frac)
+ IF (out_reserve_balance.frac >= in_reserve_payment.frac)
THEN
- my_balance_val=my_balance_val - in_reserve_payment_val;
- my_balance_frac=my_balance_frac - in_reserve_payment_frac;
+ my_balance.val=out_reserve_balance.val - in_reserve_payment.val;
+ my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac;
ELSE
- my_balance_val=my_balance_val - in_reserve_payment_val - 1;
- my_balance_frac=my_balance_frac + 100000000 - in_reserve_payment_frac;
+ my_balance.val=out_reserve_balance.val - in_reserve_payment.val - 1;
+ my_balance.frac=out_reserve_balance.frac + 100000000 - in_reserve_payment.frac;
END IF;
ELSE
- IF (my_balance_val = in_reserve_payment_val) AND (my_balance_frac >= in_reserve_payment_frac)
+ IF (out_reserve_balance.val = in_reserve_payment.val) AND (out_reserve_balance.frac >= in_reserve_payment.frac)
THEN
- my_balance_val=0;
- my_balance_frac=my_balance_frac - in_reserve_payment_frac;
+ my_balance.val=0;
+ my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac;
ELSE
- out_final_expiration = my_reserve_expiration;
- out_open_cost_val = my_cost_val;
- out_open_cost_frac = my_cost_frac;
+ out_final_expiration = reserve.expiration_date;
+ out_open_cost.val = my_cost.val;
+ out_open_cost.frac = my_cost.frac;
out_no_funds=TRUE;
RAISE NOTICE 'reserve balance too low';
RETURN;
@@ -193,17 +179,15 @@ ELSE
END IF;
UPDATE reserves SET
- current_balance_val=my_balance_val
- ,current_balance_frac=my_balance_frac
- ,gc_date=my_reserve_expiration + in_reserve_gc_delay
+ current_balance=my_balance
+ ,gc_date=reserve.expiration_date + in_reserve_gc_delay
,expiration_date=my_expiration_date
- ,purses_allowed=my_purses_allowed
+ ,purses_allowed=reserve.purses_allowed
WHERE
reserve_pub=in_reserve_pub;
out_final_expiration=my_expiration_date;
-out_open_cost_val = my_cost_val;
-out_open_cost_frac = my_cost_frac;
+out_open_cost = my_cost;
out_no_funds=FALSE;
RETURN;
diff --git a/src/exchangedb/exchange_do_reserve_open_deposit.sql b/src/exchangedb/exchange_do_reserve_open_deposit.sql
index 725122702..aa6f86a9b 100644
--- a/src/exchangedb/exchange_do_reserve_open_deposit.sql
+++ b/src/exchangedb/exchange_do_reserve_open_deposit.sql
@@ -21,8 +21,7 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_open_deposit(
IN in_coin_sig BYTEA,
IN in_reserve_sig BYTEA,
IN in_reserve_pub BYTEA,
- IN in_coin_total_val INT8,
- IN in_coin_total_frac INT4,
+ IN in_coin_total taler_amount,
OUT out_insufficient_funds BOOLEAN)
LANGUAGE plpgsql
AS $$
@@ -33,16 +32,15 @@ INSERT INTO exchange.reserves_open_deposits
,reserve_pub
,coin_pub
,coin_sig
- ,contribution_val
- ,contribution_frac
+ ,contribution
)
VALUES
(in_reserve_sig
,in_reserve_pub
,in_coin_pub
,in_coin_sig
- ,in_coin_total_val
- ,in_coin_total_frac)
+ ,in_coin_total
+ )
ON CONFLICT DO NOTHING;
IF NOT FOUND
@@ -54,24 +52,24 @@ END IF;
-- Check and update balance of the coin.
-UPDATE exchange.known_coins
+UPDATE exchange.known_coins kc
SET
- remaining_frac=remaining_frac-in_coin_total_frac
+ remaining.frac=(kc.remaining).frac-in_coin_total.frac
+ CASE
- WHEN remaining_frac < in_coin_total_frac
+ WHEN (kc.remaining).frac < in_coin_total.frac
THEN 100000000
ELSE 0
END,
- remaining_val=remaining_val-in_coin_total_val
+ remaining.val=(kc.remaining).val-in_coin_total.val
- CASE
- WHEN remaining_frac < in_coin_total_frac
+ WHEN (kc.remaining).frac < in_coin_total.frac
THEN 1
ELSE 0
END
WHERE coin_pub=in_coin_pub
- AND ( (remaining_val > in_coin_total_val) OR
- ( (remaining_frac >= in_coin_total_frac) AND
- (remaining_val >= in_coin_total_val) ) );
+ AND ( ((kc.remaining).val > in_coin_total.val) OR
+ ( ((kc.remaining).frac >= in_coin_total.frac) AND
+ ((kc.remaining).val >= in_coin_total.val) ) );
IF NOT FOUND
THEN
@@ -84,4 +82,3 @@ END IF;
out_insufficient_funds=FALSE;
END $$;
-
diff --git a/src/exchangedb/exchange_do_reserve_purse.sql b/src/exchangedb/exchange_do_reserve_purse.sql
index 0476e60d1..8ae652e69 100644
--- a/src/exchangedb/exchange_do_reserve_purse.sql
+++ b/src/exchangedb/exchange_do_reserve_purse.sql
@@ -22,8 +22,7 @@ CREATE OR REPLACE FUNCTION exchange_do_reserve_purse(
IN in_reserve_gc INT8,
IN in_reserve_sig BYTEA,
IN in_reserve_quota BOOLEAN,
- IN in_purse_fee_val INT8,
- IN in_purse_fee_frac INT4,
+ IN in_purse_fee taler_amount,
IN in_reserve_pub BYTEA,
IN in_wallet_h_payto BYTEA,
OUT out_no_funds BOOLEAN,
@@ -34,7 +33,7 @@ AS $$
BEGIN
-- Store purse merge signature, checks for purse_pub uniqueness
-INSERT INTO exchange.purse_merges
+INSERT INTO purse_merges
(partner_serial_id
,reserve_pub
,purse_pub
@@ -54,7 +53,7 @@ THEN
-- Note that by checking 'merge_sig', we implicitly check
-- identity over everything that the signature covers.
PERFORM
- FROM exchange.purse_merges
+ FROM purse_merges
WHERE purse_pub=in_purse_pub
AND merge_sig=in_merge_sig;
IF NOT FOUND
@@ -101,8 +100,8 @@ ELSE
-- UPDATE reserves balance (and check if balance is enough to pay the fee)
IF (out_no_reserve)
THEN
- IF ( (0 != in_purse_fee_val) OR
- (0 != in_purse_fee_frac) )
+ IF ( (0 != in_purse_fee.val) OR
+ (0 != in_purse_fee.frac) )
THEN
out_no_funds=TRUE;
RETURN;
@@ -118,22 +117,22 @@ ELSE
ELSE
UPDATE exchange.reserves
SET
- current_balance_frac=current_balance_frac-in_purse_fee_frac
+ current_balance.frac=(current_balance).frac-in_purse_fee.frac
+ CASE
- WHEN current_balance_frac < in_purse_fee_frac
+ WHEN (current_balance).frac < in_purse_fee.frac
THEN 100000000
ELSE 0
END,
- current_balance_val=current_balance_val-in_purse_fee_val
+ current_balance.val=(current_balance).val-in_purse_fee.val
- CASE
- WHEN current_balance_frac < in_purse_fee_frac
+ WHEN (current_balance).frac < in_purse_fee.frac
THEN 1
ELSE 0
END
WHERE reserve_pub=in_reserve_pub
- AND ( (current_balance_val > in_purse_fee_val) OR
- ( (current_balance_frac >= in_purse_fee_frac) AND
- (current_balance_val >= in_purse_fee_val) ) );
+ AND ( ((current_balance).val > in_purse_fee.val) OR
+ ( ((current_balance).frac >= in_purse_fee.frac) AND
+ ((current_balance).val >= in_purse_fee.val) ) );
IF NOT FOUND
THEN
out_no_funds=TRUE;
@@ -146,7 +145,7 @@ out_no_funds=FALSE;
-- Store account merge signature.
-INSERT INTO exchange.account_merges
+INSERT INTO account_merges
(reserve_pub
,reserve_sig
,purse_pub
@@ -159,5 +158,5 @@ INSERT INTO exchange.account_merges
END $$;
-COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, INT8, INT8, BYTEA, BOOLEAN, INT8, INT4, BYTEA, BYTEA)
+COMMENT ON FUNCTION exchange_do_reserve_purse(BYTEA, BYTEA, INT8, INT8, INT8, BYTEA, BOOLEAN, taler_amount, BYTEA, BYTEA)
IS 'Create a purse for a reserve.';
diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql
new file mode 100644
index 000000000..1be06f063
--- /dev/null
+++ b/src/exchangedb/exchange_do_reserves_in_insert.sql
@@ -0,0 +1,122 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2014--2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+
+CREATE OR REPLACE FUNCTION exchange_do_array_reserves_insert(
+ IN in_gc_date INT8,
+ IN in_reserve_expiration INT8,
+ IN ina_reserve_pub BYTEA[],
+ IN ina_wire_ref INT8[],
+ IN ina_credit taler_amount[],
+ IN ina_exchange_account_name TEXT[],
+ IN ina_execution_date INT8[],
+ IN ina_wire_source_h_payto BYTEA[],
+ IN ina_payto_uri TEXT[],
+ IN ina_notify TEXT[])
+RETURNS SETOF exchange_do_array_reserve_insert_return_type
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ conflict BOOL;
+ dup BOOL;
+ uuid INT8;
+ i INT4;
+ ini_reserve_pub BYTEA;
+ ini_wire_ref INT8;
+ ini_credit taler_amount;
+ ini_exchange_account_name TEXT;
+ ini_execution_date INT8;
+ ini_wire_source_h_payto BYTEA;
+ ini_payto_uri TEXT;
+ ini_notify TEXT;
+BEGIN
+
+ FOR i IN 1..array_length(ina_reserve_pub,1)
+ LOOP
+ ini_reserve_pub = ina_reserve_pub[i];
+ ini_wire_ref = ina_wire_ref[i];
+ ini_credit = ina_credit[i];
+ ini_exchange_account_name = ina_exchange_account_name[i];
+ ini_execution_date = ina_execution_date[i];
+ ini_wire_source_h_payto = ina_wire_source_h_payto[i];
+ ini_payto_uri = ina_payto_uri[i];
+ ini_notify = ina_notify[i];
+
+-- RAISE WARNING 'Starting loop on %', ini_notify;
+
+ INSERT INTO wire_targets
+ (wire_target_h_payto
+ ,payto_uri
+ ) VALUES (
+ ini_wire_source_h_payto
+ ,ini_payto_uri
+ )
+ ON CONFLICT DO NOTHING;
+
+ INSERT INTO reserves
+ (reserve_pub
+ ,current_balance
+ ,expiration_date
+ ,gc_date
+ ) VALUES (
+ ini_reserve_pub
+ ,ini_credit
+ ,in_reserve_expiration
+ ,in_gc_date
+ )
+ ON CONFLICT DO NOTHING
+ RETURNING reserve_uuid
+ INTO uuid;
+ conflict = NOT FOUND;
+
+ INSERT INTO reserves_in
+ (reserve_pub
+ ,wire_reference
+ ,credit
+ ,exchange_account_section
+ ,wire_source_h_payto
+ ,execution_date
+ ) VALUES (
+ ini_reserve_pub
+ ,ini_wire_ref
+ ,ini_credit
+ ,ini_exchange_account_name
+ ,ini_wire_source_h_payto
+ ,ini_execution_date
+ )
+ ON CONFLICT DO NOTHING;
+
+ IF NOT FOUND
+ THEN
+ IF conflict
+ THEN
+ dup = TRUE;
+ else
+ dup = FALSE;
+ END IF;
+ ELSE
+ IF NOT conflict
+ THEN
+ EXECUTE FORMAT (
+ 'NOTIFY %s'
+ ,ini_notify);
+ END IF;
+ dup = FALSE;
+ END IF;
+ RETURN NEXT (dup,uuid);
+ END LOOP;
+ RETURN;
+END $$;
diff --git a/src/exchangedb/exchange_do_select_deposits_missing_wire.sql b/src/exchangedb/exchange_do_select_deposits_missing_wire.sql
new file mode 100644
index 000000000..3d44a58c9
--- /dev/null
+++ b/src/exchangedb/exchange_do_select_deposits_missing_wire.sql
@@ -0,0 +1,73 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+-- @author: Christian Grothoff
+
+CREATE OR REPLACE FUNCTION exchange_do_select_deposits_missing_wire(
+ IN in_min_serial_id INT8)
+RETURNS SETOF exchange_do_select_deposits_missing_wire_return_type
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ missing CURSOR
+ FOR
+ SELECT
+ batch_deposit_serial_id
+ ,wire_target_h_payto
+ ,wire_deadline
+ FROM batch_deposits
+ WHERE batch_deposit_serial_id > in_min_serial_id
+ ORDER BY batch_deposit_serial_id ASC;
+DECLARE
+ my_total_val INT8; -- all deposits without wire
+DECLARE
+ my_total_frac INT8; -- all deposits without wire (fraction, not normalized)
+DECLARE
+ my_total taler_amount; -- amount that was originally deposited
+DECLARE
+ my_batch_record RECORD;
+DECLARE
+ i RECORD;
+BEGIN
+
+OPEN missing;
+LOOP
+ FETCH NEXT FROM missing INTO i;
+ EXIT WHEN NOT FOUND;
+
+ SELECT
+ SUM((cdep.amount_with_fee).val) AS total_val
+ ,SUM((cdep.amount_with_fee).frac::INT8) AS total_frac
+ INTO
+ my_batch_record
+ FROM coin_deposits cdep
+ WHERE cdep.batch_deposit_serial_id = i.batch_deposit_serial_id;
+
+ my_total_val=my_batch_record.total_val;
+ my_total_frac=my_batch_record.total_frac;
+
+ -- Normalize total amount
+ my_total.val = my_total_val + my_total_frac / 100000000;
+ my_total.frac = my_total_frac % 100000000;
+ RETURN NEXT (
+ i.batch_deposit_serial_id
+ ,my_total
+ ,i.wire_target_h_payto
+ ,i.wire_deadline);
+
+END LOOP;
+CLOSE missing;
+RETURN;
+END $$;
diff --git a/src/exchangedb/exchange_do_select_justification_for_missing_wire.sql b/src/exchangedb/exchange_do_select_justification_for_missing_wire.sql
new file mode 100644
index 000000000..f02a51d3d
--- /dev/null
+++ b/src/exchangedb/exchange_do_select_justification_for_missing_wire.sql
@@ -0,0 +1,102 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2023 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+-- @author: Christian Grothoff
+
+CREATE OR REPLACE FUNCTION exchange_do_select_justification_missing_wire(
+ IN in_wire_target_h_payto BYTEA,
+ IN in_current_time INT8,
+ OUT out_payto_uri TEXT, -- NULL allowed
+ OUT out_kyc_pending TEXT, -- NULL allowed
+ OUT out_aml_status INT4, -- NULL allowed
+ OUT out_aml_limit taler_amount) -- NULL allowed!
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ my_required_checks TEXT[];
+DECLARE
+ my_aml_data RECORD;
+DECLARE
+ satisfied CURSOR FOR
+ SELECT satisfied_checks
+ FROM kyc_attributes
+ WHERE h_payto=in_wire_target_h_payto
+ AND expiration_time < in_current_time;
+DECLARE
+ i RECORD;
+BEGIN
+
+ -- Fetch payto URI
+ out_payto_uri = NULL;
+ SELECT payto_uri
+ INTO out_payto_uri
+ FROM wire_targets
+ WHERE wire_target_h_payto=my_wire_target_h_payto;
+
+ -- Check KYC status
+ my_required_checks = NULL;
+ SELECT string_to_array (required_checks, ' ')
+ INTO my_required_checks
+ FROM legitimization_requirements
+ WHERE h_payto=my_wire_target_h_payto;
+
+ -- Get last AML decision
+ SELECT
+ new_threshold
+ ,kyc_requirements
+ ,new_status
+ INTO
+ my_aml_data
+ FROM aml_history
+ WHERE h_payto=in_wire_target_h_payto
+ ORDER BY aml_history_serial_id -- get last decision
+ DESC LIMIT 1;
+ IF FOUND
+ THEN
+ out_aml_limit=my_aml_data.new_threshold;
+ out_aml_status=my_aml_data.kyc_status;
+ -- Combine KYC requirements
+ my_required_checks
+ = array_cat (my_required_checks,
+ my_aml_data.kyc_requirements);
+ ELSE
+ out_aml_limit=NULL;
+ out_aml_status=0; -- or NULL? Style question!
+ END IF;
+
+ OPEN satisfied;
+ LOOP
+ FETCH NEXT FROM satisfied INTO i;
+ EXIT WHEN NOT FOUND;
+
+ -- remove all satisfied checks from the list
+ FOR i in 1..array_length(i.satisfied_checks)
+ LOOP
+ my_required_checks
+ = array_remove (my_required_checks,
+ i.satisfied_checks[i]);
+ END LOOP;
+ END LOOP;
+
+ -- Return remaining required checks as one string
+ IF ( (my_required_checks IS NOT NULL) AND
+ (0 < array_length(my_satisfied_checks)) )
+ THEN
+ out_kyc_pending
+ = array_to_string (my_required_checks, ' ');
+ END IF;
+
+ RETURN;
+END $$;
diff --git a/src/exchangedb/exchange_do_withdraw.sql b/src/exchangedb/exchange_do_withdraw.sql
deleted file mode 100644
index 9689bae5a..000000000
--- a/src/exchangedb/exchange_do_withdraw.sql
+++ /dev/null
@@ -1,199 +0,0 @@
---
--- This file is part of TALER
--- Copyright (C) 2014--2022 Taler Systems SA
---
--- TALER is free software; you can redistribute it and/or modify it under the
--- terms of the GNU General Public License as published by the Free Software
--- Foundation; either version 3, or (at your option) any later version.
---
--- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
--- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
--- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along with
--- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
---
-
-
-CREATE OR REPLACE FUNCTION exchange_do_withdraw(
- IN cs_nonce BYTEA,
- IN amount_val INT8,
- IN amount_frac INT4,
- IN h_denom_pub BYTEA,
- IN rpub BYTEA,
- IN reserve_sig BYTEA,
- IN h_coin_envelope BYTEA,
- IN denom_sig BYTEA,
- IN now INT8,
- IN min_reserve_gc INT8,
- OUT reserve_found BOOLEAN,
- OUT balance_ok BOOLEAN,
- OUT nonce_ok BOOLEAN,
- OUT ruuid INT8)
-LANGUAGE plpgsql
-AS $$
-DECLARE
- reserve_gc INT8;
-DECLARE
- denom_serial INT8;
-DECLARE
- reserve_val INT8;
-DECLARE
- reserve_frac INT4;
-BEGIN
--- Shards: reserves by reserve_pub (SELECT)
--- reserves_out (INSERT, with CONFLICT detection) by wih
--- reserves by reserve_pub (UPDATE)
--- reserves_in by reserve_pub (SELECT)
--- wire_targets by wire_target_h_payto
-
-SELECT denominations_serial
- INTO denom_serial
- FROM exchange.denominations
- WHERE denom_pub_hash=h_denom_pub;
-
-IF NOT FOUND
-THEN
- -- denomination unknown, should be impossible!
- reserve_found=FALSE;
- balance_ok=FALSE;
- ruuid=0;
- ASSERT false, 'denomination unknown';
- RETURN;
-END IF;
-
-
-SELECT
- current_balance_val
- ,current_balance_frac
- ,gc_date
- ,reserve_uuid
- INTO
- reserve_val
- ,reserve_frac
- ,reserve_gc
- ,ruuid
- FROM exchange.reserves
- WHERE reserves.reserve_pub=rpub;
-
-IF NOT FOUND
-THEN
- -- reserve unknown
- reserve_found=FALSE;
- balance_ok=FALSE;
- nonce_ok=TRUE;
- ruuid=2;
- RETURN;
-END IF;
-
--- We optimistically insert, and then on conflict declare
--- the query successful due to idempotency.
-INSERT INTO exchange.reserves_out
- (h_blind_ev
- ,denominations_serial
- ,denom_sig
- ,reserve_uuid
- ,reserve_sig
- ,execution_date
- ,amount_with_fee_val
- ,amount_with_fee_frac)
-VALUES
- (h_coin_envelope
- ,denom_serial
- ,denom_sig
- ,ruuid
- ,reserve_sig
- ,now
- ,amount_val
- ,amount_frac)
-ON CONFLICT DO NOTHING;
-
-IF NOT FOUND
-THEN
- -- idempotent query, all constraints must be satisfied
- reserve_found=TRUE;
- balance_ok=TRUE;
- nonce_ok=TRUE;
- RETURN;
-END IF;
-
--- Check reserve balance is sufficient.
-IF (reserve_val > amount_val)
-THEN
- IF (reserve_frac >= amount_frac)
- THEN
- reserve_val=reserve_val - amount_val;
- reserve_frac=reserve_frac - amount_frac;
- ELSE
- reserve_val=reserve_val - amount_val - 1;
- reserve_frac=reserve_frac + 100000000 - amount_frac;
- END IF;
-ELSE
- IF (reserve_val = amount_val) AND (reserve_frac >= amount_frac)
- THEN
- reserve_val=0;
- reserve_frac=reserve_frac - amount_frac;
- ELSE
- reserve_found=TRUE;
- nonce_ok=TRUE; -- we do not really know
- balance_ok=FALSE;
- RETURN;
- END IF;
-END IF;
-
--- Calculate new expiration dates.
-min_reserve_gc=GREATEST(min_reserve_gc,reserve_gc);
-
--- Update reserve balance.
-UPDATE reserves SET
- gc_date=min_reserve_gc
- ,current_balance_val=reserve_val
- ,current_balance_frac=reserve_frac
-WHERE
- reserves.reserve_pub=rpub;
-
-reserve_found=TRUE;
-balance_ok=TRUE;
-
-
-
--- Special actions needed for a CS withdraw?
-IF NOT NULL cs_nonce
-THEN
- -- Cache CS signature to prevent replays in the future
- -- (and check if cached signature exists at the same time).
- INSERT INTO exchange.cs_nonce_locks
- (nonce
- ,max_denomination_serial
- ,op_hash)
- VALUES
- (cs_nonce
- ,denom_serial
- ,h_coin_envelope)
- ON CONFLICT DO NOTHING;
-
- IF NOT FOUND
- THEN
- -- See if the existing entry is identical.
- SELECT 1
- FROM exchange.cs_nonce_locks
- WHERE nonce=cs_nonce
- AND op_hash=h_coin_envelope;
- IF NOT FOUND
- THEN
- reserve_found=FALSE;
- balance_ok=FALSE;
- nonce_ok=FALSE;
- RETURN;
- END IF;
- END IF;
-ELSE
- nonce_ok=TRUE; -- no nonce, hence OK!
-END IF;
-
-END $$;
-
-
-COMMENT ON FUNCTION exchange_do_withdraw(BYTEA, INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, BYTEA, INT8, INT8)
- IS 'Checks whether the reserve has sufficient balance for a withdraw operation (or the request is repeated and was previously approved) and if so updates the database with the result';
-
diff --git a/src/exchangedb/exchangedb-postgres.conf b/src/exchangedb/exchangedb-postgres.conf
index e481940ce..726d28576 100644
--- a/src/exchangedb/exchangedb-postgres.conf
+++ b/src/exchangedb/exchangedb-postgres.conf
@@ -1,9 +1,9 @@
[exchangedb-postgres]
-CONFIG = "postgres:///taler"
+CONFIG = "postgres:///taler-exchange"
# Where are the SQL files to setup our tables?
# Important: this MUST end with a "/"!
-SQL_DIR = $DATADIR/sql/exchange/
+SQL_DIR = ${DATADIR}sql/exchange/
# Number of purses per account by default.
DEFAULT_PURSE_LIMIT = 1 \ No newline at end of file
diff --git a/src/exchangedb/exchangedb_accounts.c b/src/exchangedb/exchangedb_accounts.c
index e41074822..3f0e47afb 100644
--- a/src/exchangedb/exchangedb_accounts.c
+++ b/src/exchangedb/exchangedb_accounts.c
@@ -190,28 +190,35 @@ add_account_cb (void *cls,
( (credit) &&
(lc->credit) ) ) )
return; /* not enabled for us, skip */
- if (GNUNET_OK !=
+ if (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_string (cfg,
section,
"PAYTO_URI",
&payto_uri))
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- section,
- "PAYTO_URI");
- lc->res = GNUNET_SYSERR;
- return;
+ method = TALER_payto_get_method (payto_uri);
+ GNUNET_free (payto_uri);
+ if (NULL == method)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "payto URI in config ([%s]/PAYTO_URI) malformed\n",
+ section);
+ lc->res = GNUNET_SYSERR;
+ return;
+ }
}
- method = TALER_payto_get_method (payto_uri);
- GNUNET_free (payto_uri);
- if (NULL == method)
+ else if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "WIRE_METHOD",
+ &method))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "payto URI in config ([%s]/PAYTO_URI) malformed\n",
- section);
- lc->res = GNUNET_SYSERR;
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ section,
+ "WIRE_METHOD");
return;
}
+ GNUNET_assert (NULL != method);
wa = GNUNET_new (struct WireAccount);
wa->section_name = GNUNET_strdup (section);
wa->method = method;
diff --git a/src/exchangedb/perf-exchangedb-reserves-in-insert-postgres b/src/exchangedb/perf-exchangedb-reserves-in-insert-postgres
new file mode 100755
index 000000000..8eafde3ce
--- /dev/null
+++ b/src/exchangedb/perf-exchangedb-reserves-in-insert-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# perf-exchangedb-reserves-in-insert-postgres - temporary wrapper script for .libs/perf-exchangedb-reserves-in-insert-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The perf-exchangedb-reserves-in-insert-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "perf-exchangedb-reserves-in-insert-postgres:perf-exchangedb-reserves-in-insert-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "perf-exchangedb-reserves-in-insert-postgres:perf-exchangedb-reserves-in-insert-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "perf-exchangedb-reserves-in-insert-postgres:perf-exchangedb-reserves-in-insert-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='perf-exchangedb-reserves-in-insert-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/perf_deposits_get_ready.c b/src/exchangedb/perf_deposits_get_ready.c
index 4ad08223c..005ea6843 100644
--- a/src/exchangedb/perf_deposits_get_ready.c
+++ b/src/exchangedb/perf_deposits_get_ready.c
@@ -16,7 +16,7 @@
/**
* @file exchangedb/perf_deposits_get_ready.c
* @brief benchmark for deposits_get_ready
- * @author Joseph Xu
+git * @author Joseph Xu
*/
#include "platform.h"
#include "taler_exchangedb_lib.h"
@@ -33,24 +33,25 @@ static int result;
* Report line of error if @a cond is true, and jump to label "drop".
*/
#define FAILIF(cond) \
- do { \
- if (! (cond)) {break;} \
- GNUNET_break (0); \
- goto drop; \
- } while (0)
+ do { \
+ if (! (cond)) {break;} \
+ GNUNET_break (0); \
+ goto drop; \
+ } while (0)
/**
* Initializes @a ptr with random data.
*/
#define RND_BLK(ptr) \
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, \
+ sizeof (*ptr))
/**
* Initializes @a ptr with zeros.
*/
#define ZR_BLK(ptr) \
- memset (ptr, 0, sizeof (*ptr))
+ memset (ptr, 0, sizeof (*ptr))
/**
* Currency we use. Must match test-exchange-db-*.conf.
@@ -121,7 +122,7 @@ create_denom_key_pair (unsigned int size,
GNUNET_assert (GNUNET_OK ==
TALER_denom_priv_create (&dkp->priv,
&dkp->pub,
- TALER_DENOMINATION_RSA,
+ GNUNET_CRYPTO_BSA_RSA,
size));
memset (&dki,
0,
@@ -196,19 +197,24 @@ run (void *cls)
struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
unsigned long long sqrs = 0;
- struct TALER_EXCHANGEDB_Deposit *depos = NULL;
- struct TALER_EXCHANGEDB_Refund *ref = NULL;
+ struct TALER_EXCHANGEDB_CoinDepositInformation *depos;
+ struct TALER_EXCHANGEDB_BatchDeposit bd;
+ struct TALER_EXCHANGEDB_Refund *ref;
unsigned int *perm;
unsigned long long duration_sq;
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
+ struct GNUNET_CRYPTO_BlindingInputValues bi = {
+ .cipher = GNUNET_CRYPTO_BSA_RSA,
+ .rc = 0
+ };
struct TALER_ExchangeWithdrawValues alg_values = {
- .cipher = TALER_DENOMINATION_RSA
+ .blinding_inputs = &bi
};
ref = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refund);
depos = GNUNET_new_array (ROUNDS + 1,
- struct TALER_EXCHANGEDB_Deposit);
+ struct TALER_EXCHANGEDB_CoinDepositInformation);
if (NULL ==
(plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
@@ -261,7 +267,7 @@ run (void *cls)
for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
{
struct GNUNET_TIME_Timestamp now;
- struct TALER_BlindedRsaPlanchet *rp;
+ struct GNUNET_CRYPTO_RsaBlindedMessage *rp;
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
@@ -273,8 +279,10 @@ run (void *cls)
new_denom_pubs[cnt] = new_dkp[cnt]->pub;
ccoin = &revealed_coins[cnt];
bp = &ccoin->blinded_planchet;
- bp->cipher = TALER_DENOMINATION_RSA;
- rp = &bp->details.rsa_blinded_planchet;
+ bp->blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ bp->blinded_message->cipher = GNUNET_CRYPTO_BSA_RSA;
+ bp->blinded_message->rc = 1;
+ rp = &bp->blinded_message->details.rsa_blinded_message;
rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
GNUNET_CRYPTO_QUALITY_WEAK,
(RSA_KEY_SIZE / 8) - 1);
@@ -293,10 +301,9 @@ run (void *cls)
&new_dkp[cnt]->priv,
true,
bp));
- GNUNET_assert (GNUNET_OK ==
- TALER_coin_ev_hash (bp,
- &cbc.denom_pub_hash,
- &cbc.h_coin_envelope));
+ TALER_coin_ev_hash (bp,
+ &cbc.denom_pub_hash,
+ &cbc.h_coin_envelope);
GNUNET_assert (
GNUNET_OK ==
TALER_denom_sign_blinded (
@@ -314,16 +321,16 @@ run (void *cls)
for (unsigned int j = 0; j < NUM_ROWS; j++)
{
/*** NEED TO INSERT REFRESH COMMITMENTS + ENSURECOIN ***/
- union TALER_DenominationBlindingKeyP bks;
+ union GNUNET_CRYPTO_BlindingSecretP bks;
struct GNUNET_TIME_Timestamp deadline;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_CoinPubHashP c_hash;
unsigned int k = (unsigned int) rand () % 5;
unsigned int i = perm[j];
+
if (i >= ROUNDS)
i = ROUNDS; /* throw-away slot, do not keep around */
- depos[i].deposit_fee = fees.deposit;
RND_BLK (&coin_pub);
RND_BLK (&c_hash);
RND_BLK (&reserve_pub);
@@ -331,7 +338,7 @@ run (void *cls)
TALER_denom_pub_hash (&new_dkp[k]->pub,
&cbc.denom_pub_hash);
deadline = GNUNET_TIME_timestamp_get ();
- RND_BLK (&depos[i].coin.coin_pub);
+ depos[i].coin.coin_pub = coin_pub;
TALER_denom_pub_hash (&new_dkp[k]->pub,
&depos[i].coin.denom_pub_hash);
GNUNET_assert (GNUNET_OK ==
@@ -341,19 +348,21 @@ run (void *cls)
&c_hash,
&alg_values,
&new_dkp[k]->pub));
- RND_BLK (&depos[i].merchant_pub);
+ RND_BLK (&bd.merchant_pub);
RND_BLK (&depos[i].csig);
- RND_BLK (&depos[i].h_contract_terms);
- RND_BLK (&depos[i].wire_salt);
+ RND_BLK (&bd.h_contract_terms);
+ RND_BLK (&bd.wire_salt);
depos[i].amount_with_fee = value;
- depos[i].refund_deadline = deadline;
- depos[i].wire_deadline = deadline;
- depos[i].receiver_wire_account =
+ bd.refund_deadline = deadline;
+ bd.wire_deadline = deadline;
+ bd.receiver_wire_account =
"payto://iban/DE67830654080004822650?receiver-name=Test";
TALER_merchant_wire_signature_hash (
- "payto://iban/DE67830654080004822650?receiver-name=Test",
- &depos[i].wire_salt,
+ bd.receiver_wire_account,
+ &bd.wire_salt,
&h_wire_wt);
+ bd.num_cdis = 1;
+ bd.cdis = &depos[i];
cbc.reserve_pub = reserve_pub;
cbc.amount_with_fee = value;
GNUNET_assert (GNUNET_OK ==
@@ -361,21 +370,38 @@ run (void *cls)
&cbc.withdraw_fee));
{
bool found;
- bool nonce_ok;
+ bool nonce_reuse;
bool balance_ok;
+ bool age_ok;
+ bool conflict;
+ bool denom_unknown;
+ struct TALER_Amount reserve_balance;
+ uint16_t allowed_minimum_age;
uint64_t ruuid;
struct GNUNET_TIME_Timestamp now;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->do_withdraw (plugin->cls,
- NULL,
- &cbc,
- now,
- &found,
- &balance_ok,
- &nonce_ok,
- &ruuid));
+ plugin->do_batch_withdraw (plugin->cls,
+ now,
+ &reserve_pub,
+ &value,
+ true,
+ &found,
+ &balance_ok,
+ &reserve_balance,
+ &age_ok,
+ &allowed_minimum_age,
+ &ruuid));
+ FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ plugin->do_batch_withdraw_insert (plugin->cls,
+ NULL,
+ &cbc,
+ now,
+ ruuid,
+ &denom_unknown,
+ &conflict,
+ &nonce_reuse));
}
{
/* ENSURE_COIN_KNOWN */
@@ -396,12 +422,18 @@ run (void *cls)
}
{
struct GNUNET_TIME_Timestamp now;
+ bool balance_ok;
+ uint32_t bad_idx;
+ bool ctr_conflict;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->insert_deposit (plugin->cls,
- now,
- &depos[i]));
+ plugin->do_deposit (plugin->cls,
+ &bd,
+ &now,
+ &balance_ok,
+ &bad_idx,
+ &ctr_conflict));
}
if (ROUNDS == i)
TALER_denom_sig_free (&depos[i].coin.denom_sig);
diff --git a/src/exchangedb/perf_get_link_data.c b/src/exchangedb/perf_get_link_data.c
index eb1f5f6e2..817789afc 100644
--- a/src/exchangedb/perf_get_link_data.c
+++ b/src/exchangedb/perf_get_link_data.c
@@ -110,7 +110,7 @@ create_denom_key_pair (unsigned int size,
GNUNET_assert (GNUNET_OK ==
TALER_denom_priv_create (&dkp->priv,
&dkp->pub,
- TALER_DENOMINATION_RSA,
+ GNUNET_CRYPTO_BSA_RSA,
size));
memset (&dki,
0,
@@ -208,8 +208,12 @@ run (void *cls)
struct TALER_EXCHANGEDB_Refund *ref = NULL;
unsigned int *perm;
unsigned long long duration_sq;
+ struct GNUNET_CRYPTO_BlindingInputValues bi = {
+ .cipher = GNUNET_CRYPTO_BSA_RSA,
+ .rc = 0
+ };
struct TALER_ExchangeWithdrawValues alg_values = {
- .cipher = TALER_DENOMINATION_RSA
+ .blinding_inputs = &bi
};
ref = GNUNET_new_array (ROUNDS + 1,
@@ -280,7 +284,7 @@ run (void *cls)
"Transaction"));
for (unsigned int j = 0; j < NUM_ROWS; j++)
{
- union TALER_DenominationBlindingKeyP bks;
+ union GNUNET_CRYPTO_BlindingSecretP bks;
struct TALER_CoinPubHashP c_hash;
unsigned int i = perm[j];
uint64_t known_coin_id;
@@ -303,13 +307,16 @@ run (void *cls)
struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin =
&revealed_coins[p];
struct TALER_BlindedPlanchet *bp = &revealed_coin->blinded_planchet;
- struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet;
+ bp->blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ struct GNUNET_CRYPTO_RsaBlindedMessage *rp =
+ &bp->blinded_message->details.rsa_blinded_message;
/* h_coin_ev must be unique, but we only have MELT_NEW_COINS created
above for NUM_ROWS iterations; instead of making "all new" coins,
we simply randomize the hash here as nobody is checking for consistency
anyway ;-) */
- bp->cipher = TALER_DENOMINATION_RSA;
+ bp->blinded_message->rc = 1;
+ bp->blinded_message->cipher = GNUNET_CRYPTO_BSA_RSA;
rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
GNUNET_CRYPTO_QUALITY_WEAK,
(RSA_KEY_SIZE / 8) - 1);
diff --git a/src/exchangedb/perf_reserves_in_insert.c b/src/exchangedb/perf_reserves_in_insert.c
index 9f3ed4604..09c4a43c5 100644
--- a/src/exchangedb/perf_reserves_in_insert.c
+++ b/src/exchangedb/perf_reserves_in_insert.c
@@ -78,8 +78,9 @@ run (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
- static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 32 };
- const unsigned int lcm = 3 * 32;
+ static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 32, 64, 128, 256, 512,
+ 1024, 1024, 512, 256, 128, 64, 32,
+ 16, 4, 3, 2, 1 };
struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)];
unsigned long long sqrs[sizeof (batches) / sizeof(*batches)];
@@ -109,7 +110,7 @@ run (void *cls)
i< sizeof(batches) / sizeof(*batches);
i++)
{
- unsigned int batch_size = batches[i];
+ unsigned int lcm = batches[i];
struct TALER_Amount value;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Timestamp ts;
@@ -141,7 +142,6 @@ run (void *cls)
plugin->reserves_in_insert (plugin->cls,
reserves,
lcm,
- batch_size,
results));
}
duration = GNUNET_TIME_absolute_get_duration (now);
@@ -159,6 +159,7 @@ run (void *cls)
i< sizeof(batches) / sizeof(*batches);
i++)
{
+ unsigned int lcm = batches[i];
struct GNUNET_TIME_Relative avg;
double avg_dbl;
double variance;
@@ -168,10 +169,10 @@ run (void *cls)
avg_dbl = avg.rel_value_us;
variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS);
fprintf (stdout,
- "Batch[%2u]: %8llu ± %6.0f\n",
+ "Batch[%4u]: %8llu us/entry ± %6.0f\n",
batches[i],
- (unsigned long long) avg.rel_value_us,
- sqrt (variance / (ROUNDS - 1)));
+ (unsigned long long) avg.rel_value_us / lcm,
+ sqrt (variance / lcm / (ROUNDS - 1)));
}
result = 0;
drop:
diff --git a/src/exchangedb/perf_select_refunds_by_coin.c b/src/exchangedb/perf_select_refunds_by_coin.c
index 85c92f4b9..84825d6d7 100644
--- a/src/exchangedb/perf_select_refunds_by_coin.c
+++ b/src/exchangedb/perf_select_refunds_by_coin.c
@@ -33,23 +33,24 @@ static int result;
* Report line of error if @a cond is true, and jump to label "drop".
*/
#define FAILIF(cond) \
- do { \
- if (! (cond)) {break;} \
- GNUNET_break (0); \
- goto drop; \
- } while (0)
+ do { \
+ if (! (cond)) {break;} \
+ GNUNET_break (0); \
+ goto drop; \
+ } while (0)
/**
* Initializes @a ptr with random data.
*/
#define RND_BLK(ptr) \
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, \
+ sizeof (*ptr))
/**
* Initializes @a ptr with zeros.
*/
#define ZR_BLK(ptr) \
- memset (ptr, 0, sizeof (*ptr))
+ memset (ptr, 0, sizeof (*ptr))
/**
* Currency we use. Must match test-exchange-db-*.conf.
@@ -117,7 +118,7 @@ create_denom_key_pair (unsigned int size,
GNUNET_assert (GNUNET_OK ==
TALER_denom_priv_create (&dkp->priv,
&dkp->pub,
- TALER_DENOMINATION_RSA,
+ GNUNET_CRYPTO_BSA_RSA,
size));
memset (&dki,
0,
@@ -211,21 +212,23 @@ run (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
struct GNUNET_TIME_Timestamp ts;
- struct TALER_EXCHANGEDB_Deposit *depos = NULL;
+ struct TALER_EXCHANGEDB_CoinDepositInformation *depos = NULL;
struct GNUNET_TIME_Timestamp deadline;
struct TALER_Amount value;
- union TALER_DenominationBlindingKeyP bks;
- struct TALER_CoinPubHashP c_hash;
+ union GNUNET_CRYPTO_BlindingSecretP bks;
struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
+ struct GNUNET_CRYPTO_BlindingInputValues bi = {
+ .cipher = GNUNET_CRYPTO_BSA_RSA,
+ .rc = 0
+ };
struct TALER_ExchangeWithdrawValues alg_values = {
- .cipher = TALER_DENOMINATION_RSA
+ .blinding_inputs = &bi
};
struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
unsigned long long sqrs = 0;
struct TALER_EXCHANGEDB_Refund *ref = NULL;
unsigned int *perm;
unsigned long long duration_sq;
- struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
unsigned int count = 0;
@@ -233,7 +236,7 @@ run (void *cls)
ref = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refund);
depos = GNUNET_new_array (ROUNDS + 1,
- struct TALER_EXCHANGEDB_Deposit);
+ struct TALER_EXCHANGEDB_CoinDepositInformation);
ZR_BLK (&cbc);
if (NULL ==
@@ -289,7 +292,7 @@ run (void *cls)
for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
{
struct GNUNET_TIME_Timestamp now;
- struct TALER_BlindedRsaPlanchet *rp;
+ struct GNUNET_CRYPTO_RsaBlindedMessage *rp;
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
@@ -301,8 +304,10 @@ run (void *cls)
new_denom_pubs[cnt] = new_dkp[cnt]->pub;
ccoin = &revealed_coins[cnt];
bp = &ccoin->blinded_planchet;
- bp->cipher = TALER_DENOMINATION_RSA;
- rp = &bp->details.rsa_blinded_planchet;
+ bp->blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ bp->blinded_message->rc = 1;
+ bp->blinded_message->cipher = GNUNET_CRYPTO_BSA_RSA;
+ rp = &bp->blinded_message->details.rsa_blinded_message;
rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
GNUNET_CRYPTO_QUALITY_WEAK,
(RSA_KEY_SIZE / 8) - 1);
@@ -321,10 +326,9 @@ run (void *cls)
&new_dkp[cnt]->priv,
true,
bp));
- GNUNET_assert (GNUNET_OK ==
- TALER_coin_ev_hash (bp,
- &cbc.denom_pub_hash,
- &cbc.h_coin_envelope));
+ TALER_coin_ev_hash (bp,
+ &cbc.denom_pub_hash,
+ &cbc.h_coin_envelope);
GNUNET_assert (
GNUNET_OK ==
TALER_denom_sign_blinded (
@@ -344,55 +348,68 @@ run (void *cls)
{
unsigned int i = perm[j];
unsigned int k = (unsigned int) rand () % 5;
+ struct TALER_CoinPubHashP c_hash;
+ uint64_t known_coin_id;
+ struct TALER_EXCHANGEDB_CoinDepositInformation *cdi
+ = &depos[i];
+ struct TALER_EXCHANGEDB_BatchDeposit bd = {
+ .cdis = cdi,
+ .num_cdis = 1,
+ .wallet_timestamp = ts,
+ .refund_deadline = deadline,
+ .wire_deadline = deadline,
+ .receiver_wire_account
+ = "payto://iban/DE67830654080004822650?receiver-name=Test"
+ };
+
if (i >= ROUNDS)
i = ROUNDS; /* throw-away slot, do not keep around */
- RND_BLK (&coin_pub);
+ RND_BLK (&bd.merchant_pub);
+ RND_BLK (&bd.h_contract_terms);
+ RND_BLK (&bd.wire_salt);
+ TALER_merchant_wire_signature_hash (
+ bd.receiver_wire_account,
+ &bd.wire_salt,
+ &h_wire_wt);
+ RND_BLK (&cdi->coin.coin_pub);
+ RND_BLK (&cdi->csig);
RND_BLK (&c_hash);
- depos[i].deposit_fee = fees.deposit;
- RND_BLK (&depos[i].coin.coin_pub);
TALER_denom_pub_hash (&new_dkp[k]->pub,
- &depos[i].coin.denom_pub_hash);
+ &cdi->coin.denom_pub_hash);
GNUNET_assert (GNUNET_OK ==
- TALER_denom_sig_unblind (&depos[i].coin.denom_sig,
+ TALER_denom_sig_unblind (&cdi->coin.denom_sig,
&cbc.sig,
&bks,
&c_hash,
&alg_values,
&new_dkp[k]->pub));
- RND_BLK (&depos[i].merchant_pub);
- RND_BLK (&depos[i].csig);
- RND_BLK (&depos[i].h_contract_terms);
- RND_BLK (&depos[i].wire_salt);
- depos[i].amount_with_fee = value;
- depos[i].refund_deadline = deadline;
- depos[i].wire_deadline = deadline;
- depos[i].receiver_wire_account =
- "payto://iban/DE67830654080004822650?receiver-name=Test";
- TALER_merchant_wire_signature_hash (
- "payto://iban/DE67830654080004822650?receiver-name=Test",
- &depos[i].wire_salt,
- &h_wire_wt);
- depos[i].timestamp = ts;
- uint64_t known_coin_id;
+ cdi->amount_with_fee = value;
+
{
struct TALER_DenominationHashP dph;
struct TALER_AgeCommitmentHash agh;
FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
plugin->ensure_coin_known (plugin->cls,
- &depos[i].coin,
+ &cdi->coin,
&known_coin_id,
&dph,
&agh));
}
{
struct GNUNET_TIME_Timestamp now;
+ bool balance_ok;
+ uint32_t bad_idx;
+ bool in_conflict;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->insert_deposit (plugin->cls,
- now,
- &depos[i]));
+ plugin->do_deposit (plugin->cls,
+ &bd,
+ &now,
+ &balance_ok,
+ &bad_idx,
+ &in_conflict));
}
{
bool not_found;
@@ -404,9 +421,9 @@ run (void *cls)
{
case 2: // 100% refund
ref[i].coin = depos[i].coin;
- ref[i].details.merchant_pub = depos[i].merchant_pub;
+ ref[i].details.merchant_pub = bd.merchant_pub;
RND_BLK (&ref[i].details.merchant_sig);
- ref[i].details.h_contract_terms = depos[i].h_contract_terms;
+ ref[i].details.h_contract_terms = bd.h_contract_terms;
ref[i].coin.coin_pub = depos[i].coin.coin_pub;
ref[i].details.rtransaction_id = i;
ref[i].details.refund_amount = value;
@@ -425,9 +442,9 @@ run (void *cls)
if (count < (NUM_ROWS / 10))
{
ref[i].coin = depos[i].coin;
- ref[i].details.merchant_pub = depos[i].merchant_pub;
+ ref[i].details.merchant_pub = bd.merchant_pub;
RND_BLK (&ref[i].details.merchant_sig);
- ref[i].details.h_contract_terms = depos[i].h_contract_terms;
+ ref[i].details.h_contract_terms = bd.h_contract_terms;
ref[i].coin.coin_pub = depos[i].coin.coin_pub;
ref[i].details.rtransaction_id = i;
ref[i].details.refund_amount = value;
diff --git a/src/exchangedb/pg_abort_shard.h b/src/exchangedb/pg_abort_shard.h
index 070b48dab..e52ace5f6 100644
--- a/src/exchangedb/pg_abort_shard.h
+++ b/src/exchangedb/pg_abort_shard.h
@@ -36,7 +36,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_abort_shard (void *cls,
- const char *job_name,
- uint64_t start_row,
+ const char *job_name,
+ uint64_t start_row,
uint64_t end_row);
+
#endif
diff --git a/src/exchangedb/pg_add_denomination_key.c b/src/exchangedb/pg_add_denomination_key.c
index e115a44ec..eb50304d3 100644
--- a/src/exchangedb/pg_add_denomination_key.c
+++ b/src/exchangedb/pg_add_denomination_key.c
@@ -43,11 +43,16 @@ TEH_PG_add_denomination_key (
GNUNET_PQ_query_param_timestamp (&meta->expire_withdraw),
GNUNET_PQ_query_param_timestamp (&meta->expire_deposit),
GNUNET_PQ_query_param_timestamp (&meta->expire_legal),
- TALER_PQ_query_param_amount (&meta->value),
- TALER_PQ_query_param_amount (&meta->fees.withdraw),
- TALER_PQ_query_param_amount (&meta->fees.deposit),
- TALER_PQ_query_param_amount (&meta->fees.refresh),
- TALER_PQ_query_param_amount (&meta->fees.refund),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->value),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->fees.withdraw),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->fees.deposit),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->fees.refresh),
+ TALER_PQ_query_param_amount (pg->conn,
+ &meta->fees.refund),
GNUNET_PQ_query_param_uint32 (&meta->age_mask.bits),
GNUNET_PQ_query_param_end
};
@@ -56,8 +61,6 @@ TEH_PG_add_denomination_key (
GNUNET_assert (GNUNET_YES ==
TALER_denom_fee_check_currency (meta->value.currency,
&meta->fees));
- /* Used in #postgres_insert_denomination_info() and
- #postgres_add_denomination_key() */
PREPARE (pg,
"denomination_insert",
"INSERT INTO denominations "
@@ -68,22 +71,16 @@ TEH_PG_add_denomination_key (
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin" /* value of this denom */
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",age_mask"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17, $18);");
+ " $11, $12, $13);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"denomination_insert",
iparams);
}
-
diff --git a/src/exchangedb/pg_add_policy_fulfillment_proof.c b/src/exchangedb/pg_add_policy_fulfillment_proof.c
index bb06206ae..93d070712 100644
--- a/src/exchangedb/pg_add_policy_fulfillment_proof.c
+++ b/src/exchangedb/pg_add_policy_fulfillment_proof.c
@@ -55,6 +55,7 @@ TEH_PG_add_policy_fulfillment_proof (
enum GNUNET_DB_QueryStatus qs;
struct PostgresClosure *pg = cls;
size_t count = fulfillment->details_count;
+ /* FIXME: this seems to be prone to VLA attacks */
struct GNUNET_HashCode hcs[count];
/* Create the sorted policy_hash_codes */
@@ -84,8 +85,7 @@ TEH_PG_add_policy_fulfillment_proof (
GNUNET_PQ_query_param_timestamp (&fulfillment->timestamp),
TALER_PQ_query_param_json (fulfillment->proof),
GNUNET_PQ_query_param_auto_from_type (&fulfillment->h_proof),
- GNUNET_PQ_query_param_fixed_size (hcs,
- count * sizeof(struct GNUNET_HashCode)),
+ TALER_PQ_query_param_array_hash_code (count, hcs, pg->conn),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -94,7 +94,15 @@ TEH_PG_add_policy_fulfillment_proof (
GNUNET_PQ_result_spec_end
};
-
+ PREPARE (pg,
+ "insert_proof_into_policy_fulfillments",
+ "INSERT INTO policy_fulfillments"
+ "(fulfillment_timestamp"
+ ",fulfillment_proof"
+ ",h_fulfillment_proof"
+ ",policy_hash_codes"
+ ") VALUES ($1, $2, $3, $4)"
+ " ON CONFLICT DO NOTHING;");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"insert_proof_into_policy_fulfillments",
params,
@@ -112,14 +120,28 @@ TEH_PG_add_policy_fulfillment_proof (
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&pos->hash_code),
GNUNET_PQ_query_param_timestamp (&pos->deadline),
- TALER_PQ_query_param_amount (&pos->commitment),
- TALER_PQ_query_param_amount (&pos->accumulated_total),
- TALER_PQ_query_param_amount (&pos->policy_fee),
- TALER_PQ_query_param_amount (&pos->transferable_amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ &pos->commitment),
+ TALER_PQ_query_param_amount (pg->conn,
+ &pos->accumulated_total),
+ TALER_PQ_query_param_amount (pg->conn,
+ &pos->policy_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &pos->transferable_amount),
GNUNET_PQ_query_param_auto_from_type (&pos->fulfillment_state),
GNUNET_PQ_query_param_end
};
+ PREPARE (pg,
+ "update_policy_details",
+ "UPDATE policy_details SET"
+ " deadline=$2"
+ ",commitment=$3"
+ ",accumulated_total=$4"
+ ",fee=$5"
+ ",transferable=$6"
+ ",fulfillment_state=$7"
+ " WHERE policy_hash_code=$1;");
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_policy_details",
params);
@@ -128,5 +150,10 @@ TEH_PG_add_policy_fulfillment_proof (
}
}
+ /*
+ * FIXME[oec]-#7999: When all policies of a deposit are fulfilled,
+ * unblock it and trigger a wire-transfer.
+ */
+
return qs;
}
diff --git a/src/exchangedb/pg_aggregate.c b/src/exchangedb/pg_aggregate.c
index 6e94cbebb..ba03e4a9c 100644
--- a/src/exchangedb/pg_aggregate.c
+++ b/src/exchangedb/pg_aggregate.c
@@ -22,9 +22,12 @@
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
+#include "pg_compute_shard.h"
+#include "pg_event_notify.h"
#include "pg_aggregate.h"
#include "pg_helper.h"
+
enum GNUNET_DB_QueryStatus
TEH_PG_aggregate (
void *cls,
@@ -34,35 +37,14 @@ TEH_PG_aggregate (
struct TALER_Amount *total)
{
struct PostgresClosure *pg = cls;
+ uint64_t deposit_shard = TEH_PG_compute_shard (merchant_pub);
struct GNUNET_TIME_Absolute now = {0};
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_payto),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
uint64_t sum_deposit_value;
uint64_t sum_deposit_frac;
uint64_t sum_refund_value;
uint64_t sum_refund_frac;
uint64_t sum_fee_value;
uint64_t sum_fee_frac;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("sum_deposit_value",
- &sum_deposit_value),
- GNUNET_PQ_result_spec_uint64 ("sum_deposit_fraction",
- &sum_deposit_frac),
- GNUNET_PQ_result_spec_uint64 ("sum_refund_value",
- &sum_refund_value),
- GNUNET_PQ_result_spec_uint64 ("sum_refund_fraction",
- &sum_refund_frac),
- GNUNET_PQ_result_spec_uint64 ("sum_fee_value",
- &sum_fee_value),
- GNUNET_PQ_result_spec_uint64 ("sum_fee_fraction",
- &sum_fee_frac),
- GNUNET_PQ_result_spec_end
- };
enum GNUNET_DB_QueryStatus qs;
struct TALER_Amount sum_deposit;
struct TALER_Amount sum_refund;
@@ -71,61 +53,63 @@ TEH_PG_aggregate (
now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (),
pg->aggregator_shift);
-
- /* Used in #postgres_aggregate() */
PREPARE (pg,
"aggregate",
- "WITH dep AS (" /* restrict to our merchant and account and mark as done */
- " UPDATE deposits"
+ "WITH bdep AS (" /* restrict to our merchant and account and mark as done */
+ " UPDATE batch_deposits"
" SET done=TRUE"
" WHERE NOT (done OR policy_blocked)" /* only actually executable deposits */
- " AND refund_deadline<$1" /* filter by shard */
+ " AND refund_deadline<$1"
+ " AND shard=$5" /* only for efficiency, merchant_pub is what we really filter by */
" AND merchant_pub=$2" /* filter by target merchant */
" AND wire_target_h_payto=$3" /* merchant could have a 2nd bank account */
" RETURNING"
- " deposit_serial_id"
+ " batch_deposit_serial_id)"
+ " ,cdep AS ("
+ " SELECT"
+ " coin_deposit_serial_id"
+ " ,batch_deposit_serial_id"
" ,coin_pub"
- " ,amount_with_fee_val AS amount_val"
- " ,amount_with_fee_frac AS amount_frac)"
+ " ,amount_with_fee AS amount"
+ " FROM coin_deposits"
+ " WHERE batch_deposit_serial_id IN (SELECT batch_deposit_serial_id FROM bdep))"
" ,ref AS (" /* find applicable refunds -- NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
" SELECT"
- " amount_with_fee_val AS refund_val"
- " ,amount_with_fee_frac AS refund_frac"
+ " amount_with_fee AS refund"
" ,coin_pub"
- " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
+ " ,batch_deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
" FROM refunds"
- " WHERE coin_pub IN (SELECT coin_pub FROM dep)"
- " AND deposit_serial_id IN (SELECT deposit_serial_id FROM dep))"
+ " WHERE coin_pub IN (SELECT coin_pub FROM cdep)"
+ " AND batch_deposit_serial_id IN (SELECT batch_deposit_serial_id FROM bdep))"
" ,ref_by_coin AS (" /* total up refunds by coin */
" SELECT"
- " SUM(refund_val) AS sum_refund_val"
- " ,SUM(refund_frac) AS sum_refund_frac"
+ " SUM((ref.refund).val) AS sum_refund_val"
+ " ,SUM((ref.refund).frac) AS sum_refund_frac"
" ,coin_pub"
- " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
+ " ,batch_deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
" FROM ref"
- " GROUP BY coin_pub, deposit_serial_id)"
+ " GROUP BY coin_pub, batch_deposit_serial_id)"
" ,norm_ref_by_coin AS (" /* normalize */
" SELECT"
" sum_refund_val + sum_refund_frac / 100000000 AS norm_refund_val"
" ,sum_refund_frac % 100000000 AS norm_refund_frac"
" ,coin_pub"
- " ,deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
+ " ,batch_deposit_serial_id" /* theoretically, coin could be in multiple refunded transactions */
" FROM ref_by_coin)"
" ,fully_refunded_coins AS (" /* find applicable refunds -- NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
" SELECT"
- " dep.coin_pub"
+ " cdep.coin_pub"
" FROM norm_ref_by_coin norm"
- " JOIN dep"
- " ON (norm.coin_pub = dep.coin_pub"
- " AND norm.deposit_serial_id = dep.deposit_Serial_id"
- " AND norm.norm_refund_val = dep.amount_val"
- " AND norm.norm_refund_frac = dep.amount_frac))"
+ " JOIN cdep"
+ " ON (norm.coin_pub = cdep.coin_pub"
+ " AND norm.batch_deposit_serial_id = cdep.batch_deposit_serial_id"
+ " AND norm.norm_refund_val = (cdep.amount).val"
+ " AND norm.norm_refund_frac = (cdep.amount).frac))"
" ,fees AS (" /* find deposit fees for not fully refunded deposits */
" SELECT"
- " denom.fee_deposit_val AS fee_val"
- " ,denom.fee_deposit_frac AS fee_frac"
- " ,cs.deposit_serial_id" /* ensures we get the fee for each coin, not once per denomination */
- " FROM dep cs"
+ " denom.fee_deposit AS fee"
+ " ,cs.batch_deposit_serial_id" /* ensures we get the fee for each coin, not once per denomination */
+ " FROM cdep cs"
" JOIN known_coins kc" /* NOTE: may do a full join on the master, maybe find a left-join way to integrate with query above to push it to the shards? */
" USING (coin_pub)"
" JOIN denominations denom"
@@ -133,26 +117,52 @@ TEH_PG_aggregate (
" WHERE coin_pub NOT IN (SELECT coin_pub FROM fully_refunded_coins))"
" ,dummy AS (" /* add deposits to aggregation_tracking */
" INSERT INTO aggregation_tracking"
- " (deposit_serial_id"
+ " (batch_deposit_serial_id"
" ,wtid_raw)"
- " SELECT deposit_serial_id,$4"
- " FROM dep)"
+ " SELECT batch_deposit_serial_id,$4"
+ " FROM bdep)"
"SELECT" /* calculate totals (deposits, refunds and fees) */
- " CAST(COALESCE(SUM(dep.amount_val),0) AS INT8) AS sum_deposit_value" /* cast needed, otherwise we get NUMBER */
- " ,COALESCE(SUM(dep.amount_frac),0) AS sum_deposit_fraction" /* SUM over INT returns INT8 */
- " ,CAST(COALESCE(SUM(ref.refund_val),0) AS INT8) AS sum_refund_value"
- " ,COALESCE(SUM(ref.refund_frac),0) AS sum_refund_fraction"
- " ,CAST(COALESCE(SUM(fees.fee_val),0) AS INT8) AS sum_fee_value"
- " ,COALESCE(SUM(fees.fee_frac),0) AS sum_fee_fraction"
- " FROM dep "
+ " CAST(COALESCE(SUM((cdep.amount).val),0) AS INT8) AS sum_deposit_value"
+ /* cast needed, otherwise we get NUMBER */
+ " ,COALESCE(SUM((cdep.amount).frac),0) AS sum_deposit_fraction" /* SUM over INT returns INT8 */
+ " ,CAST(COALESCE(SUM((ref.refund).val),0) AS INT8) AS sum_refund_value"
+ " ,COALESCE(SUM((ref.refund).frac),0) AS sum_refund_fraction"
+ " ,CAST(COALESCE(SUM((fees.fee).val),0) AS INT8) AS sum_fee_value"
+ " ,COALESCE(SUM((fees.fee).frac),0) AS sum_fee_fraction"
+ " FROM cdep "
" FULL OUTER JOIN ref ON (FALSE)" /* We just want all sums */
" FULL OUTER JOIN fees ON (FALSE);");
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_uint64 (&deposit_shard),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("sum_deposit_value",
+ &sum_deposit_value),
+ GNUNET_PQ_result_spec_uint64 ("sum_deposit_fraction",
+ &sum_deposit_frac),
+ GNUNET_PQ_result_spec_uint64 ("sum_refund_value",
+ &sum_refund_value),
+ GNUNET_PQ_result_spec_uint64 ("sum_refund_fraction",
+ &sum_refund_frac),
+ GNUNET_PQ_result_spec_uint64 ("sum_fee_value",
+ &sum_fee_value),
+ GNUNET_PQ_result_spec_uint64 ("sum_fee_fraction",
+ &sum_fee_frac),
+ GNUNET_PQ_result_spec_end
+ };
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "aggregate",
- params,
- rs);
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "aggregate",
+ params,
+ rs);
+ }
if (qs < 0)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
diff --git a/src/exchangedb/pg_batch_ensure_coin_known.c b/src/exchangedb/pg_batch_ensure_coin_known.c
new file mode 100644
index 000000000..aca2732c6
--- /dev/null
+++ b/src/exchangedb/pg_batch_ensure_coin_known.c
@@ -0,0 +1,462 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_batch_ensure_coin_known.c
+ * @brief Implementation of the batch_ensure_coin_known function for Postgres
+ * @author Christian Grothoff
+ *
+ * FIXME: use the array support for postgres to simplify this code!
+ *
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_exchangedb_plugin.h"
+#include "taler_pq_lib.h"
+#include "pg_batch_ensure_coin_known.h"
+#include "pg_helper.h"
+
+
+static enum GNUNET_DB_QueryStatus
+insert1 (struct PostgresClosure *pg,
+ const struct TALER_CoinPublicInfo coin[1],
+ struct TALER_EXCHANGEDB_CoinInfo result[1])
+{
+ enum GNUNET_DB_QueryStatus qs;
+ bool is_denom_pub_hash_null = false;
+ bool is_age_hash_null = false;
+ PREPARE (pg,
+ "batch1_known_coin",
+ "SELECT"
+ " existed1 AS existed"
+ ",known_coin_id1 AS known_coin_id"
+ ",denom_pub_hash1 AS denom_hash"
+ ",age_commitment_hash1 AS h_age_commitment"
+ " FROM exchange_do_batch1_known_coin"
+ " ($1, $2, $3, $4);"
+ );
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("existed",
+ &result[0].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+ &result[0].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+ &result[0].denom_hash),
+ &is_denom_pub_hash_null),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
+ &result[0].h_age_commitment),
+ &is_age_hash_null),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "batch1_known_coin",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return qs;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0); /* should be impossible */
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break; /* continued below */
+ }
+
+ if ( (! is_denom_pub_hash_null) &&
+ (0 != GNUNET_memcmp (&result[0].denom_hash,
+ &coin->denom_pub_hash)) )
+ {
+ GNUNET_break_op (0);
+ result[0].denom_conflict = true;
+ }
+
+ if ( (! is_denom_pub_hash_null) &&
+ (0 != GNUNET_memcmp (&result[0].denom_hash,
+ &coin[0].denom_pub_hash)) )
+ {
+ GNUNET_break_op (0);
+ result[0].denom_conflict = true;
+ }
+
+ result[0].age_conflict = TALER_AgeCommitmentHash_NoConflict;
+
+ if (is_age_hash_null != coin[0].no_age_commitment)
+ {
+ if (is_age_hash_null)
+ {
+ GNUNET_break_op (0);
+ result[0].age_conflict = TALER_AgeCommitmentHash_NullExpected;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ result[0].age_conflict = TALER_AgeCommitmentHash_ValueExpected;
+ }
+ }
+ else if ( (! is_age_hash_null) &&
+ (0 != GNUNET_memcmp (&result[0].h_age_commitment,
+ &coin[0].h_age_commitment)) )
+ {
+ GNUNET_break_op (0);
+ result[0].age_conflict = TALER_AgeCommitmentHash_ValueDiffers;
+ }
+
+ return qs;
+}
+
+
+static enum GNUNET_DB_QueryStatus
+insert2 (struct PostgresClosure *pg,
+ const struct TALER_CoinPublicInfo coin[2],
+ struct TALER_EXCHANGEDB_CoinInfo result[2])
+{
+ enum GNUNET_DB_QueryStatus qs;
+ bool is_denom_pub_hash_null[2] = {false, false};
+ bool is_age_hash_null[2] = {false, false};
+
+ PREPARE (pg,
+ "batch2_known_coin",
+ "SELECT"
+ " existed1 AS existed"
+ ",known_coin_id1 AS known_coin_id"
+ ",denom_pub_hash1 AS denom_hash"
+ ",age_commitment_hash1 AS h_age_commitment"
+ ",existed2 AS existed2"
+ ",known_coin_id2 AS known_coin_id2"
+ ",denom_pub_hash2 AS denom_hash2"
+ ",age_commitment_hash2 AS h_age_commitment2"
+ " FROM exchange_do_batch2_known_coin"
+ " ($1, $2, $3, $4, $5, $6, $7, $8);"
+ );
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
+
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("existed",
+ &result[0].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+ &result[0].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+ &result[0].denom_hash),
+ &is_denom_pub_hash_null[0]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
+ &result[0].h_age_commitment),
+ &is_age_hash_null[0]),
+ GNUNET_PQ_result_spec_bool ("existed2",
+ &result[1].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
+ &result[1].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
+ &result[1].denom_hash),
+ &is_denom_pub_hash_null[1]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
+ &result[1].h_age_commitment),
+ &is_age_hash_null[1]),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "batch2_known_coin",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return qs;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0); /* should be impossible */
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break; /* continued below */
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ if ( (! is_denom_pub_hash_null[i]) &&
+ (0 != GNUNET_memcmp (&result[i].denom_hash,
+ &coin[i].denom_pub_hash)) )
+ {
+ GNUNET_break_op (0);
+ result[i].denom_conflict = true;
+ }
+
+ result[i].age_conflict = TALER_AgeCommitmentHash_NoConflict;
+
+ if (is_age_hash_null[i] != coin[i].no_age_commitment)
+ {
+ if (is_age_hash_null[i])
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_NullExpected;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_ValueExpected;
+ }
+ }
+ else if ( (! is_age_hash_null[i]) &&
+ (0 != GNUNET_memcmp (&result[i].h_age_commitment,
+ &coin[i].h_age_commitment)) )
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_ValueDiffers;
+ }
+ }
+
+ return qs;
+}
+
+
+static enum GNUNET_DB_QueryStatus
+insert4 (struct PostgresClosure *pg,
+ const struct TALER_CoinPublicInfo coin[4],
+ struct TALER_EXCHANGEDB_CoinInfo result[4])
+{
+ enum GNUNET_DB_QueryStatus qs;
+ bool is_denom_pub_hash_null[4] = {false, false, false, false};
+ bool is_age_hash_null[4] = {false, false, false, false};
+ PREPARE (pg,
+ "batch4_known_coin",
+ "SELECT"
+ " existed1 AS existed"
+ ",known_coin_id1 AS known_coin_id"
+ ",denom_pub_hash1 AS denom_hash"
+ ",age_commitment_hash1 AS h_age_commitment"
+ ",existed2 AS existed2"
+ ",known_coin_id2 AS known_coin_id2"
+ ",denom_pub_hash2 AS denom_hash2"
+ ",age_commitment_hash2 AS h_age_commitment2"
+ ",existed3 AS existed3"
+ ",known_coin_id3 AS known_coin_id3"
+ ",denom_pub_hash3 AS denom_hash3"
+ ",age_commitment_hash3 AS h_age_commitment3"
+ ",existed4 AS existed4"
+ ",known_coin_id4 AS known_coin_id4"
+ ",denom_pub_hash4 AS denom_hash4"
+ ",age_commitment_hash4 AS h_age_commitment4"
+ " FROM exchange_do_batch2_known_coin"
+ " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);"
+ );
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[0].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
+
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[1].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[0].denom_sig),
+
+ GNUNET_PQ_query_param_auto_from_type (&coin[2].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[2].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[2].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[2].denom_sig),
+
+ GNUNET_PQ_query_param_auto_from_type (&coin[3].coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&coin[3].denom_pub_hash),
+ GNUNET_PQ_query_param_auto_from_type (&coin[3].h_age_commitment),
+ TALER_PQ_query_param_denom_sig (&coin[3].denom_sig),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("existed",
+ &result[0].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+ &result[0].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+ &result[0].denom_hash),
+ &is_denom_pub_hash_null[0]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
+ &result[0].h_age_commitment),
+ &is_age_hash_null[0]),
+ GNUNET_PQ_result_spec_bool ("existed2",
+ &result[1].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id2",
+ &result[1].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash2",
+ &result[1].denom_hash),
+ &is_denom_pub_hash_null[1]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash2",
+ &result[1].h_age_commitment),
+ &is_age_hash_null[1]),
+ GNUNET_PQ_result_spec_bool ("existed3",
+ &result[2].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id3",
+ &result[2].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash3",
+ &result[2].denom_hash),
+ &is_denom_pub_hash_null[2]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash3",
+ &result[2].h_age_commitment),
+ &is_age_hash_null[2]),
+ GNUNET_PQ_result_spec_bool ("existed4",
+ &result[3].existed),
+ GNUNET_PQ_result_spec_uint64 ("known_coin_id4",
+ &result[3].known_coin_id),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash4",
+ &result[3].denom_hash),
+ &is_denom_pub_hash_null[3]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash4",
+ &result[3].h_age_commitment),
+ &is_age_hash_null[3]),
+ GNUNET_PQ_result_spec_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "batch4_known_coin",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return qs;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0); /* should be impossible */
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break; /* continued below */
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ if ( (! is_denom_pub_hash_null[i]) &&
+ (0 != GNUNET_memcmp (&result[i].denom_hash,
+ &coin[i].denom_pub_hash)) )
+ {
+ GNUNET_break_op (0);
+ result[i].denom_conflict = true;
+ }
+
+ result[i].age_conflict = TALER_AgeCommitmentHash_NoConflict;
+
+ if (is_age_hash_null[i] != coin[i].no_age_commitment)
+ {
+ if (is_age_hash_null[i])
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_NullExpected;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_ValueExpected;
+ }
+ }
+ else if ( (! is_age_hash_null[i]) &&
+ (0 != GNUNET_memcmp (&result[i].h_age_commitment,
+ &coin[i].h_age_commitment)) )
+ {
+ GNUNET_break_op (0);
+ result[i].age_conflict = TALER_AgeCommitmentHash_ValueDiffers;
+ }
+ }
+
+ return qs;
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_batch_ensure_coin_known (
+ void *cls,
+ const struct TALER_CoinPublicInfo *coin,
+ struct TALER_EXCHANGEDB_CoinInfo *result,
+ unsigned int coin_length,
+ unsigned int batch_size)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs = 0;
+ unsigned int i = 0;
+
+ while ( (qs >= 0) &&
+ (i < coin_length) )
+ {
+ unsigned int bs = GNUNET_MIN (batch_size,
+ coin_length - i);
+ if (bs >= 4)
+ {
+ qs = insert4 (pg,
+ &coin[i],
+ &result[i]);
+ i += 4;
+ continue;
+ }
+ switch (bs)
+ {
+ case 3:
+ case 2:
+ qs = insert2 (pg,
+ &coin[i],
+ &result[i]);
+ i += 2;
+ break;
+ case 1:
+ qs = insert1 (pg,
+ &coin[i],
+ &result[i]);
+ i += 1;
+ break;
+ case 0:
+ GNUNET_assert (0);
+ break;
+ }
+ } /* end while */
+ if (qs < 0)
+ return qs;
+ return i;
+}
diff --git a/src/exchangedb/pg_batch_ensure_coin_known.h b/src/exchangedb/pg_batch_ensure_coin_known.h
new file mode 100644
index 000000000..2c53676d9
--- /dev/null
+++ b/src/exchangedb/pg_batch_ensure_coin_known.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022, 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_batch_ensure_coin_known.h
+ * @brief implementation of the batch_ensure_coin_known function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_BATCH_ENSURE_COIN_KNOWN_H
+#define PG_BATCH_ENSURE_COIN_KNOWN_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Make sure the array of given @a coin is known to the database.
+ *
+ * @param cls database connection plugin state
+ * @param coin array of coins that must be made known
+ * @param[out] result array where to store information about each coin
+ * @param coin_length length of the @a coin and @a result arraysf
+ * @param batch_size desired (maximum) batch size
+ * @return database transaction status, non-negative on success
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_batch_ensure_coin_known (
+ void *cls,
+ const struct TALER_CoinPublicInfo *coin,
+ struct TALER_EXCHANGEDB_CoinInfo *result,
+ unsigned int coin_length,
+ unsigned int batch_size);
+
+#endif
diff --git a/src/exchangedb/pg_begin_revolving_shard.c b/src/exchangedb/pg_begin_revolving_shard.c
index 888d7fd20..86cdf80fd 100644
--- a/src/exchangedb/pg_begin_revolving_shard.c
+++ b/src/exchangedb/pg_begin_revolving_shard.c
@@ -30,11 +30,11 @@
enum GNUNET_DB_QueryStatus
TEH_PG_begin_revolving_shard (void *cls,
- const char *job_name,
- uint32_t shard_size,
- uint32_t shard_limit,
- uint32_t *start_row,
- uint32_t *end_row)
+ const char *job_name,
+ uint32_t shard_size,
+ uint32_t shard_limit,
+ uint32_t *start_row,
+ uint32_t *end_row)
{
struct PostgresClosure *pg = cls;
@@ -45,7 +45,7 @@ TEH_PG_begin_revolving_shard (void *cls,
{
if (GNUNET_OK !=
TEH_PG_start (pg,
- "begin_revolving_shard"))
+ "begin_revolving_shard"))
{
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
@@ -64,15 +64,15 @@ TEH_PG_begin_revolving_shard (void *cls,
&last_end),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_begin_revolving_shard() */
- PREPARE(pg,
- "get_last_revolving_shard",
- "SELECT"
- " end_row"
- " FROM revolving_work_shards"
- " WHERE job_name=$1"
- " ORDER BY end_row DESC"
- " LIMIT 1;");
+ /* Used in #postgres_begin_revolving_shard() */
+ PREPARE (pg,
+ "get_last_revolving_shard",
+ "SELECT"
+ " end_row"
+ " FROM revolving_work_shards"
+ " WHERE job_name=$1"
+ " ORDER BY end_row DESC"
+ " LIMIT 1;");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_last_revolving_shard",
params,
@@ -116,7 +116,7 @@ TEH_PG_begin_revolving_shard (void *cls,
(unsigned long long) *start_row,
(unsigned long long) *end_row);
- /* Used in #postgres_claim_revolving_shard() */
+ /* Used in #postgres_claim_revolving_shard() */
PREPARE (pg,
"create_revolving_shard",
"INSERT INTO revolving_work_shards"
@@ -164,7 +164,7 @@ TEH_PG_begin_revolving_shard (void *cls,
end_row),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_begin_revolving_shard() */
+ /* Used in #postgres_begin_revolving_shard() */
PREPARE (pg,
"get_open_revolving_shard",
"SELECT"
@@ -206,7 +206,7 @@ TEH_PG_begin_revolving_shard (void *cls,
now = GNUNET_TIME_timestamp_get ();
- /* Used in #postgres_begin_revolving_shard() */
+ /* Used in #postgres_begin_revolving_shard() */
PREPARE (pg,
"reclaim_revolving_shard",
"UPDATE revolving_work_shards"
diff --git a/src/exchangedb/pg_begin_revolving_shard.h b/src/exchangedb/pg_begin_revolving_shard.h
index bdbca4f11..0755f886b 100644
--- a/src/exchangedb/pg_begin_revolving_shard.h
+++ b/src/exchangedb/pg_begin_revolving_shard.h
@@ -40,9 +40,10 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_begin_revolving_shard (void *cls,
- const char *job_name,
- uint32_t shard_size,
- uint32_t shard_limit,
- uint32_t *start_row,
+ const char *job_name,
+ uint32_t shard_size,
+ uint32_t shard_limit,
+ uint32_t *start_row,
uint32_t *end_row);
+
#endif
diff --git a/src/exchangedb/pg_begin_shard.h b/src/exchangedb/pg_begin_shard.h
index 39bd834e9..16f19491d 100644
--- a/src/exchangedb/pg_begin_shard.h
+++ b/src/exchangedb/pg_begin_shard.h
@@ -38,10 +38,10 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_begin_shard (void *cls,
- const char *job_name,
- struct GNUNET_TIME_Relative delay,
- uint64_t shard_size,
- uint64_t *start_row,
+ const char *job_name,
+ struct GNUNET_TIME_Relative delay,
+ uint64_t shard_size,
+ uint64_t *start_row,
uint64_t *end_row);
#endif
diff --git a/src/exchangedb/pg_commit.c b/src/exchangedb/pg_commit.c
index f1e61ee34..8c4f87c90 100644
--- a/src/exchangedb/pg_commit.c
+++ b/src/exchangedb/pg_commit.c
@@ -45,7 +45,7 @@ TEH_PG_commit (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Committing transaction `%s'\n",
pg->transaction_name);
- /* used in #postgres_commit */
+ /* used in #postgres_commit */
PREPARE (pg,
"do_commit",
"COMMIT");
diff --git a/src/exchangedb/pg_complete_shard.h b/src/exchangedb/pg_complete_shard.h
index 8693f402e..f06c0483b 100644
--- a/src/exchangedb/pg_complete_shard.h
+++ b/src/exchangedb/pg_complete_shard.h
@@ -36,7 +36,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_complete_shard (void *cls,
- const char *job_name,
- uint64_t start_row,
+ const char *job_name,
+ uint64_t start_row,
uint64_t end_row);
+
#endif
diff --git a/src/exchangedb/pg_count_known_coins.c b/src/exchangedb/pg_count_known_coins.c
index 28c4612fc..872965ac9 100644
--- a/src/exchangedb/pg_count_known_coins.c
+++ b/src/exchangedb/pg_count_known_coins.c
@@ -27,8 +27,8 @@
long long
TEH_PG_count_known_coins (void *cls,
- const struct
- TALER_DenominationHashP *denom_pub_hash)
+ const struct
+ TALER_DenominationHashP *denom_pub_hash)
{
struct PostgresClosure *pg = cls;
uint64_t count;
diff --git a/src/exchangedb/pg_count_known_coins.h b/src/exchangedb/pg_count_known_coins.h
index f5dd4f27f..69f07bdf4 100644
--- a/src/exchangedb/pg_count_known_coins.h
+++ b/src/exchangedb/pg_count_known_coins.h
@@ -33,7 +33,7 @@
*/
long long
TEH_PG_count_known_coins (void *cls,
- const struct
+ const struct
TALER_DenominationHashP *denom_pub_hash);
#endif
diff --git a/src/exchangedb/pg_create_aggregation_transient.c b/src/exchangedb/pg_create_aggregation_transient.c
index 4ced9da04..4ab537d3a 100644
--- a/src/exchangedb/pg_create_aggregation_transient.c
+++ b/src/exchangedb/pg_create_aggregation_transient.c
@@ -38,7 +38,8 @@ TEH_PG_create_aggregation_transient (
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (total),
+ TALER_PQ_query_param_amount (pg->conn,
+ total),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
@@ -46,18 +47,17 @@ TEH_PG_create_aggregation_transient (
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_create_aggregation_transient() */
+
PREPARE (pg,
- "create_aggregation_transient",
- "INSERT INTO aggregation_transient"
- " (amount_val"
- " ,amount_frac"
- " ,merchant_pub"
- " ,wire_target_h_payto"
- " ,legitimization_requirement_serial_id"
- " ,exchange_account_section"
- " ,wtid_raw)"
- " VALUES ($1, $2, $3, $4, $5, $6, $7);");
+ "create_aggregation_transient",
+ "INSERT INTO aggregation_transient"
+ " (amount"
+ " ,merchant_pub"
+ " ,wire_target_h_payto"
+ " ,legitimization_requirement_serial_id"
+ " ,exchange_account_section"
+ " ,wtid_raw)"
+ " VALUES ($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"create_aggregation_transient",
params);
diff --git a/src/exchangedb/pg_create_tables.c b/src/exchangedb/pg_create_tables.c
index 1d5728d89..f6a061904 100644
--- a/src/exchangedb/pg_create_tables.c
+++ b/src/exchangedb/pg_create_tables.c
@@ -52,7 +52,6 @@ TEH_PG_create_tables (void *cls,
GNUNET_PQ_EXECUTE_STATEMENT_END
};
-
conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
"exchangedb-postgres",
"exchange-",
diff --git a/src/exchangedb/pg_delete_aggregation_transient.c b/src/exchangedb/pg_delete_aggregation_transient.c
index d0622c0f7..63c5c0a23 100644
--- a/src/exchangedb/pg_delete_aggregation_transient.c
+++ b/src/exchangedb/pg_delete_aggregation_transient.c
@@ -48,5 +48,3 @@ TEH_PG_delete_aggregation_transient (
"delete_aggregation_transient",
params);
}
-
-
diff --git a/src/exchangedb/pg_delete_shard_locks.c b/src/exchangedb/pg_delete_shard_locks.c
index e55cf25ff..dbb0f29ac 100644
--- a/src/exchangedb/pg_delete_shard_locks.c
+++ b/src/exchangedb/pg_delete_shard_locks.c
@@ -39,4 +39,3 @@ TEH_PG_delete_shard_locks (void *cls)
return GNUNET_PQ_exec_statements (pg->conn,
es);
}
-
diff --git a/src/exchangedb/pg_do_age_withdraw.c b/src/exchangedb/pg_do_age_withdraw.c
new file mode 100644
index 000000000..970e65b5d
--- /dev/null
+++ b/src/exchangedb/pg_do_age_withdraw.c
@@ -0,0 +1,108 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_do_batch_withdraw.c
+ * @brief Implementation of the do_batch_withdraw function for Postgres
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_exchangedb_plugin.h"
+#include "taler_pq_lib.h"
+#include "taler_pq_lib.h"
+#include "pg_do_batch_withdraw.h"
+#include "pg_helper.h"
+#include <gnunet/gnunet_time_lib.h>
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_age_withdraw (
+ void *cls,
+ const struct TALER_EXCHANGEDB_AgeWithdraw *commitment,
+ struct GNUNET_TIME_Timestamp now,
+ bool *found,
+ bool *balance_ok,
+ struct TALER_Amount *reserve_balance,
+ bool *age_ok,
+ uint16_t *required_age,
+ uint32_t *reserve_birthday,
+ bool *conflict)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Timestamp gc;
+ struct GNUNET_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_amount (pg->conn,
+ &commitment->amount_with_fee),
+ GNUNET_PQ_query_param_auto_from_type (&commitment->reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (&commitment->reserve_sig),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_timestamp (&gc),
+ GNUNET_PQ_query_param_auto_from_type (&commitment->h_commitment),
+ GNUNET_PQ_query_param_uint16 (&commitment->max_age),
+ GNUNET_PQ_query_param_uint16 (&commitment->noreveal_index),
+ TALER_PQ_query_param_array_blinded_coin_hash (commitment->num_coins,
+ commitment->h_coin_evs,
+ pg->conn),
+ GNUNET_PQ_query_param_array_uint64 (commitment->num_coins,
+ commitment->denom_serials,
+ pg->conn),
+ TALER_PQ_query_param_array_blinded_denom_sig (commitment->num_coins,
+ commitment->denom_sigs,
+ pg->conn),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("reserve_found",
+ found),
+ GNUNET_PQ_result_spec_bool ("balance_ok",
+ balance_ok),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("reserve_balance",
+ reserve_balance),
+ GNUNET_PQ_result_spec_bool ("age_ok",
+ age_ok),
+ GNUNET_PQ_result_spec_uint16 ("required_age",
+ required_age),
+ GNUNET_PQ_result_spec_uint32 ("reserve_birthday",
+ reserve_birthday),
+ GNUNET_PQ_result_spec_bool ("conflict",
+ conflict),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ gc = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_absolute_add (now.abs_time,
+ pg->legal_reserve_expiration_time));
+ PREPARE (pg,
+ "call_age_withdraw",
+ "SELECT "
+ " reserve_found"
+ ",balance_ok"
+ ",reserve_balance"
+ ",age_ok"
+ ",required_age"
+ ",reserve_birthday"
+ ",conflict"
+ " FROM exchange_do_age_withdraw"
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "call_age_withdraw",
+ params,
+ rs);
+ GNUNET_PQ_cleanup_query_params_closures (params);
+ return qs;
+}
diff --git a/src/exchangedb/pg_do_age_withdraw.h b/src/exchangedb/pg_do_age_withdraw.h
new file mode 100644
index 000000000..fb435a309
--- /dev/null
+++ b/src/exchangedb/pg_do_age_withdraw.h
@@ -0,0 +1,57 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_do_age_withdraw.h
+ * @brief implementation of the do_age_withdraw function for Postgres
+ * @author Özgür Kesim
+ */
+#ifndef PG_DO_AGE_WITHDRAW_H
+#define PG_DO_AGE_WITHDRAW_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Perform reserve update as part of an age-withdraw operation, checking for
+ * sufficient balance and fulfillment of age requirements. Finally persisting
+ * the withdrawal details.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param commitment the commitment with all parameters
+ * @param now current time (rounded)
+ * @param[out] found set to true if the reserve was found
+ * @param[out] balance_ok set to true if the balance was sufficient
+ * @param[out] reserve_balance set to the original reserve balance (at the start of this transaction)
+ * @param[out] age_ok set to true if no age requirements are present on the reserve
+ * @param[out] required_age if @e age_ok is false, set to the maximum allowed age when withdrawing from this reserve
+ * @param[out] reserve_birthday if @e age_ok is false, set to the birthday of the reserve
+ * @param[out] conflict set to true if there already is an entry in the database for the given pair (h_commitment, reserve_pub)
+ * @return query execution status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_age_withdraw (
+ void *cls,
+ const struct TALER_EXCHANGEDB_AgeWithdraw *commitment,
+ const struct GNUNET_TIME_Timestamp now,
+ bool *found,
+ bool *balance_ok,
+ struct TALER_Amount *reserve_balance,
+ bool *age_ok,
+ uint16_t *required_age,
+ uint32_t *reserve_birthday,
+ bool *conflict);
+
+#endif
diff --git a/src/exchangedb/pg_do_batch_withdraw.c b/src/exchangedb/pg_do_batch_withdraw.c
index 8ef1be268..f5571ddbb 100644
--- a/src/exchangedb/pg_do_batch_withdraw.c
+++ b/src/exchangedb/pg_do_batch_withdraw.c
@@ -17,6 +17,7 @@
* @file exchangedb/pg_do_batch_withdraw.c
* @brief Implementation of the do_batch_withdraw function for Postgres
* @author Christian Grothoff
+ * @author Özgür Kesim
*/
#include "platform.h"
#include "taler_error_codes.h"
@@ -32,17 +33,23 @@ TEH_PG_do_batch_withdraw (
struct GNUNET_TIME_Timestamp now,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
+ bool do_age_check,
bool *found,
bool *balance_ok,
+ struct TALER_Amount *reserve_balance,
+ bool *age_ok,
+ uint16_t *allowed_maximum_age,
uint64_t *ruuid)
{
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Timestamp gc;
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount),
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_timestamp (&now),
GNUNET_PQ_query_param_timestamp (&gc),
+ GNUNET_PQ_query_param_bool (do_age_check),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -50,6 +57,12 @@ TEH_PG_do_batch_withdraw (
found),
GNUNET_PQ_result_spec_bool ("balance_ok",
balance_ok),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("reserve_balance",
+ reserve_balance),
+ GNUNET_PQ_result_spec_bool ("age_ok",
+ age_ok),
+ GNUNET_PQ_result_spec_uint16 ("allowed_maximum_age",
+ allowed_maximum_age),
GNUNET_PQ_result_spec_uint64 ("ruuid",
ruuid),
GNUNET_PQ_result_spec_end
@@ -58,15 +71,14 @@ TEH_PG_do_batch_withdraw (
gc = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (now.abs_time,
pg->legal_reserve_expiration_time));
-
-
- /* Used in #postgres_do_batch_withdraw() to
- update the reserve balance and check its status */
PREPARE (pg,
"call_batch_withdraw",
"SELECT "
" reserve_found"
",balance_ok"
+ ",reserve_balance"
+ ",age_ok"
+ ",allowed_maximum_age"
",ruuid"
" FROM exchange_do_batch_withdraw"
" ($1,$2,$3,$4,$5);");
@@ -75,4 +87,3 @@ TEH_PG_do_batch_withdraw (
params,
rs);
}
-
diff --git a/src/exchangedb/pg_do_batch_withdraw.h b/src/exchangedb/pg_do_batch_withdraw.h
index ee4bf2937..486f8d1b2 100644
--- a/src/exchangedb/pg_do_batch_withdraw.h
+++ b/src/exchangedb/pg_do_batch_withdraw.h
@@ -33,8 +33,12 @@
* @param now current time (rounded)
* @param reserve_pub public key of the reserve to debit
* @param amount total amount to withdraw
+ * @param age_check_required if true, fail if age requirements are set on the reserve
* @param[out] found set to true if the reserve was found
* @param[out] balance_ok set to true if the balance was sufficient
+ * @param[out] reserve_balance set to the original reserve balance (at the start of this transaction)
+ * @param[out] age_ok set to true if no age requirements are present on the reserve
+ * @param[out] allowed_maximum_age if @e age_ok is false, set to the maximum allowed age when withdrawing from this reserve (client needs to call age-withdraw)
* @param[out] ruuid set to the reserve's UUID (reserves table row)
* @return query execution status
*/
@@ -44,8 +48,12 @@ TEH_PG_do_batch_withdraw (
struct GNUNET_TIME_Timestamp now,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *amount,
+ bool age_check_required,
bool *found,
bool *balance_ok,
+ struct TALER_Amount *reserve_balance,
+ bool *age_ok,
+ uint16_t *allowed_maximum_age,
uint64_t *ruuid);
#endif
diff --git a/src/exchangedb/pg_do_batch_withdraw_insert.c b/src/exchangedb/pg_do_batch_withdraw_insert.c
index 8d3aac688..758f502f2 100644
--- a/src/exchangedb/pg_do_batch_withdraw_insert.c
+++ b/src/exchangedb/pg_do_batch_withdraw_insert.c
@@ -25,10 +25,11 @@
#include "pg_do_batch_withdraw_insert.h"
#include "pg_helper.h"
+
enum GNUNET_DB_QueryStatus
TEH_PG_do_batch_withdraw_insert (
void *cls,
- const struct TALER_CsNonce *nonce,
+ const union GNUNET_CRYPTO_BlindSessionNonce *nonce,
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
struct GNUNET_TIME_Timestamp now,
uint64_t ruuid,
@@ -41,7 +42,8 @@ TEH_PG_do_batch_withdraw_insert (
NULL == nonce
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_auto_from_type (nonce),
- TALER_PQ_query_param_amount (&collectable->amount_with_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &collectable->amount_with_fee),
GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
GNUNET_PQ_query_param_uint64 (&ruuid),
GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
@@ -59,9 +61,7 @@ TEH_PG_do_batch_withdraw_insert (
nonce_reuse),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_do_batch_withdraw_insert() to store
- the signature of a blinded coin with the blinded coin's
- details. */
+
PREPARE (pg,
"call_batch_withdraw_insert",
"SELECT "
@@ -69,7 +69,7 @@ TEH_PG_do_batch_withdraw_insert (
",out_conflict AS conflict"
",out_nonce_reuse AS nonce_reuse"
" FROM exchange_do_batch_withdraw_insert"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9);");
+ " ($1,$2,$3,$4,$5,$6,$7,$8);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_batch_withdraw_insert",
params,
diff --git a/src/exchangedb/pg_do_batch_withdraw_insert.h b/src/exchangedb/pg_do_batch_withdraw_insert.h
index 6bc1a9a45..18fcfc9ae 100644
--- a/src/exchangedb/pg_do_batch_withdraw_insert.h
+++ b/src/exchangedb/pg_do_batch_withdraw_insert.h
@@ -41,7 +41,7 @@
enum GNUNET_DB_QueryStatus
TEH_PG_do_batch_withdraw_insert (
void *cls,
- const struct TALER_CsNonce *nonce,
+ const union GNUNET_CRYPTO_BlindSessionNonce *nonce,
const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
struct GNUNET_TIME_Timestamp now,
uint64_t ruuid,
diff --git a/src/exchangedb/pg_do_deposit.c b/src/exchangedb/pg_do_deposit.c
index c8f25e5bc..0ba45b628 100644
--- a/src/exchangedb/pg_do_deposit.c
+++ b/src/exchangedb/pg_do_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -25,62 +25,95 @@
#include "pg_do_deposit.h"
#include "pg_helper.h"
#include "pg_compute_shard.h"
+
+
enum GNUNET_DB_QueryStatus
TEH_PG_do_deposit (
void *cls,
- const struct TALER_EXCHANGEDB_Deposit *deposit,
- uint64_t known_coin_id,
- const struct TALER_PaytoHashP *h_payto,
- uint64_t *policy_details_serial_id,
+ const struct TALER_EXCHANGEDB_BatchDeposit *bd,
struct GNUNET_TIME_Timestamp *exchange_timestamp,
bool *balance_ok,
- bool *in_conflict)
+ uint32_t *bad_balance_index,
+ bool *ctr_conflict)
{
struct PostgresClosure *pg = cls;
- uint64_t deposit_shard = TEH_PG_compute_shard (&deposit->merchant_pub);
+ uint64_t deposit_shard = TEH_PG_compute_shard (&bd->merchant_pub);
+ const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (bd->num_cdis)];
+ const struct TALER_CoinSpendSignatureP *coin_sigs[GNUNET_NZL (bd->num_cdis)];
+ struct TALER_Amount amounts_with_fee[GNUNET_NZL (bd->num_cdis)];
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (&deposit->amount_with_fee),
- GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&deposit->wire_salt),
- GNUNET_PQ_query_param_timestamp (&deposit->timestamp),
- GNUNET_PQ_query_param_timestamp (exchange_timestamp),
- GNUNET_PQ_query_param_timestamp (&deposit->refund_deadline),
- GNUNET_PQ_query_param_timestamp (&deposit->wire_deadline),
- GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
- GNUNET_PQ_query_param_string (deposit->receiver_wire_account),
- GNUNET_PQ_query_param_auto_from_type (h_payto),
- GNUNET_PQ_query_param_uint64 (&known_coin_id),
- GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
- GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
+ /* data for batch_deposits */
GNUNET_PQ_query_param_uint64 (&deposit_shard),
- GNUNET_PQ_query_param_bool (deposit->has_policy),
- (NULL == policy_details_serial_id)
+ GNUNET_PQ_query_param_auto_from_type (&bd->merchant_pub),
+ GNUNET_PQ_query_param_timestamp (&bd->wallet_timestamp),
+ GNUNET_PQ_query_param_timestamp (exchange_timestamp),
+ GNUNET_PQ_query_param_timestamp (&bd->refund_deadline),
+ GNUNET_PQ_query_param_timestamp (&bd->wire_deadline),
+ GNUNET_PQ_query_param_auto_from_type (&bd->h_contract_terms),
+ (bd->no_wallet_data_hash)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (&bd->wallet_data_hash),
+ GNUNET_PQ_query_param_auto_from_type (&bd->wire_salt),
+ GNUNET_PQ_query_param_auto_from_type (&bd->wire_target_h_payto),
+ (0 == bd->policy_details_serial_id)
? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_uint64 (policy_details_serial_id),
+ : GNUNET_PQ_query_param_uint64 (&bd->policy_details_serial_id),
+ GNUNET_PQ_query_param_bool (bd->policy_blocked),
+ /* to create entry in wire_targets */
+ GNUNET_PQ_query_param_string (bd->receiver_wire_account),
+ /* arrays for coin_deposits */
+ GNUNET_PQ_query_param_array_ptrs_auto_from_type (bd->num_cdis,
+ coin_pubs,
+ pg->conn),
+ GNUNET_PQ_query_param_array_ptrs_auto_from_type (bd->num_cdis,
+ coin_sigs,
+ pg->conn),
+ TALER_PQ_query_param_array_amount (bd->num_cdis,
+ amounts_with_fee,
+ pg->conn),
GNUNET_PQ_query_param_end
};
+ bool no_time;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("balance_ok",
- balance_ok),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
+ exchange_timestamp),
+ &no_time),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("insufficient_balance_coin_index",
+ bad_balance_index),
+ balance_ok),
GNUNET_PQ_result_spec_bool ("conflicted",
- in_conflict),
- GNUNET_PQ_result_spec_timestamp ("exchange_timestamp",
- exchange_timestamp),
+ ctr_conflict),
GNUNET_PQ_result_spec_end
};
+ enum GNUNET_DB_QueryStatus qs;
+
+ for (unsigned int i = 0; i < bd->num_cdis; i++)
+ {
+ const struct TALER_EXCHANGEDB_CoinDepositInformation *cdi
+ = &bd->cdis[i];
- /* Used in #postgres_do_deposit() to execute a deposit,
- checking the coin's balance in the process as needed. */
+ amounts_with_fee[i] = cdi->amount_with_fee;
+ coin_pubs[i] = &cdi->coin.coin_pub;
+ coin_sigs[i] = &cdi->csig;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Do deposit %u = %s\n",
+ i,
+ TALER_B2S (&cdi->coin.coin_pub));
+ }
PREPARE (pg,
"call_deposit",
"SELECT "
" out_exchange_timestamp AS exchange_timestamp"
- ",out_balance_ok AS balance_ok"
+ ",out_insufficient_balance_coin_index AS insufficient_balance_coin_index"
",out_conflict AS conflicted"
" FROM exchange_do_deposit"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "call_deposit",
- params,
- rs);
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16);");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "call_deposit",
+ params,
+ rs);
+ GNUNET_PQ_cleanup_query_params_closures (params);
+ return qs;
}
diff --git a/src/exchangedb/pg_do_deposit.h b/src/exchangedb/pg_do_deposit.h
index e71cf0e4b..449ec04be 100644
--- a/src/exchangedb/pg_do_deposit.h
+++ b/src/exchangedb/pg_do_deposit.h
@@ -24,29 +24,28 @@
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
+
+
/**
* Perform deposit operation, checking for sufficient balance
- * of the coin and possibly persisting the deposit details.
+ * of the coins and possibly persisting the deposit details.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param deposit deposit operation details
- * @param known_coin_id row of the coin in the known_coins table
- * @param h_payto hash of the merchant's bank account details
- * @param policy_details_serial_id pointer to the ID of the entry in policy_details, maybe NULL
+ * @param bd batch deposit operation details
* @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
* @param[out] balance_ok set to true if the balance was sufficient
+ * @param[out] bad_balance_index set to the first index of a coin for which the balance was insufficient,
+ * only used if @a balance_ok is set to false.
* @param[out] in_conflict set to true if the deposit conflicted
* @return query execution status
*/
enum GNUNET_DB_QueryStatus
TEH_PG_do_deposit (
void *cls,
- const struct TALER_EXCHANGEDB_Deposit *deposit,
- uint64_t known_coin_id,
- const struct TALER_PaytoHashP *h_payto,
- uint64_t *policy_details_serial_id,
+ const struct TALER_EXCHANGEDB_BatchDeposit *bd,
struct GNUNET_TIME_Timestamp *exchange_timestamp,
bool *balance_ok,
+ uint32_t *bad_balance_index,
bool *in_conflict);
#endif
diff --git a/src/exchangedb/pg_do_melt.c b/src/exchangedb/pg_do_melt.c
index 6f81ff38b..0b26386d8 100644
--- a/src/exchangedb/pg_do_melt.c
+++ b/src/exchangedb/pg_do_melt.c
@@ -40,7 +40,8 @@ TEH_PG_do_melt (
NULL == rms
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_auto_from_type (rms),
- TALER_PQ_query_param_amount (&refresh->amount_with_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &refresh->amount_with_fee),
GNUNET_PQ_query_param_auto_from_type (&refresh->rc),
GNUNET_PQ_query_param_auto_from_type (&refresh->coin.coin_pub),
GNUNET_PQ_query_param_auto_from_type (&refresh->coin_sig),
@@ -63,7 +64,6 @@ TEH_PG_do_melt (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_do_melt() to melt a coin. */
PREPARE (pg,
"call_melt",
"SELECT "
@@ -71,7 +71,7 @@ TEH_PG_do_melt (
",out_zombie_bad AS zombie_required"
",out_noreveal_index AS noreveal_index"
" FROM exchange_do_melt"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9);");
+ " ($1,$2,$3,$4,$5,$6,$7,$8);");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_melt",
params,
diff --git a/src/exchangedb/pg_do_purse_deposit.c b/src/exchangedb/pg_do_purse_deposit.c
index ba6f03c11..bdb1f4749 100644
--- a/src/exchangedb/pg_do_purse_deposit.c
+++ b/src/exchangedb/pg_do_purse_deposit.c
@@ -47,10 +47,14 @@ TEH_PG_do_purse_deposit (
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_uint64 (&partner_id),
GNUNET_PQ_query_param_auto_from_type (purse_pub),
- TALER_PQ_query_param_amount (amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ amount),
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_auto_from_type (coin_sig),
- TALER_PQ_query_param_amount (amount_minus_fee),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ amount_minus_fee),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_timestamp (&now),
GNUNET_PQ_query_param_end
@@ -77,7 +81,7 @@ TEH_PG_do_purse_deposit (
",out_conflict AS conflict"
",out_late AS too_late"
" FROM exchange_do_purse_deposit"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
+ " ($1,$2,$3,$4,$5,$6,$7,$8);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_purse_deposit",
diff --git a/src/exchangedb/pg_do_purse_merge.c b/src/exchangedb/pg_do_purse_merge.c
index 518b66bf6..5a174ed02 100644
--- a/src/exchangedb/pg_do_purse_merge.c
+++ b/src/exchangedb/pg_do_purse_merge.c
@@ -75,7 +75,6 @@ TEH_PG_do_purse_merge (
&h_payto);
GNUNET_free (payto_uri);
}
- /* Used in #postgres_do_purse_merge() */
PREPARE (pg,
"call_purse_merge",
"SELECT"
diff --git a/src/exchangedb/pg_do_recoup.c b/src/exchangedb/pg_do_recoup.c
index 00f7bdd8b..07566a607 100644
--- a/src/exchangedb/pg_do_recoup.c
+++ b/src/exchangedb/pg_do_recoup.c
@@ -31,7 +31,7 @@ TEH_PG_do_recoup (
void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t reserve_out_serial_id,
- const union TALER_DenominationBlindingKeyP *coin_bks,
+ const union GNUNET_CRYPTO_BlindingSecretP *coin_bks,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
@@ -70,7 +70,6 @@ TEH_PG_do_recoup (
};
-
PREPARE (pg,
"call_recoup",
"SELECT "
diff --git a/src/exchangedb/pg_do_recoup.h b/src/exchangedb/pg_do_recoup.h
index 07a350789..2cf3eb976 100644
--- a/src/exchangedb/pg_do_recoup.h
+++ b/src/exchangedb/pg_do_recoup.h
@@ -45,7 +45,7 @@ TEH_PG_do_recoup (
void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t reserve_out_serial_id,
- const union TALER_DenominationBlindingKeyP *coin_bks,
+ const union GNUNET_CRYPTO_BlindingSecretP *coin_bks,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
diff --git a/src/exchangedb/pg_do_recoup_refresh.c b/src/exchangedb/pg_do_recoup_refresh.c
index be5e4705d..7d099bcd5 100644
--- a/src/exchangedb/pg_do_recoup_refresh.c
+++ b/src/exchangedb/pg_do_recoup_refresh.c
@@ -30,7 +30,7 @@ TEH_PG_do_recoup_refresh (
void *cls,
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
uint64_t rrc_serial,
- const union TALER_DenominationBlindingKeyP *coin_bks,
+ const union GNUNET_CRYPTO_BlindingSecretP *coin_bks,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
diff --git a/src/exchangedb/pg_do_recoup_refresh.h b/src/exchangedb/pg_do_recoup_refresh.h
index 3ac0f0a07..16b0fd208 100644
--- a/src/exchangedb/pg_do_recoup_refresh.h
+++ b/src/exchangedb/pg_do_recoup_refresh.h
@@ -46,11 +46,12 @@ TEH_PG_do_recoup_refresh (
void *cls,
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
uint64_t rrc_serial,
- const union TALER_DenominationBlindingKeyP *coin_bks,
+ const union GNUNET_CRYPTO_BlindingSecretP *coin_bks,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
uint64_t known_coin_id,
const struct TALER_CoinSpendSignatureP *coin_sig,
struct GNUNET_TIME_Timestamp *recoup_timestamp,
bool *recoup_ok,
bool *internal_failure);
+
#endif
diff --git a/src/exchangedb/pg_do_refund.c b/src/exchangedb/pg_do_refund.c
index 1059f9cbb..194dab18d 100644
--- a/src/exchangedb/pg_do_refund.c
+++ b/src/exchangedb/pg_do_refund.c
@@ -25,6 +25,8 @@
#include "pg_do_refund.h"
#include "pg_helper.h"
#include "pg_compute_shard.h"
+
+
enum GNUNET_DB_QueryStatus
TEH_PG_do_refund (
void *cls,
@@ -40,9 +42,12 @@ TEH_PG_do_refund (
uint64_t deposit_shard = TEH_PG_compute_shard (&refund->details.merchant_pub);
struct TALER_Amount amount_without_fee;
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (&refund->details.refund_amount),
- TALER_PQ_query_param_amount (&amount_without_fee),
- TALER_PQ_query_param_amount (deposit_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &refund->details.refund_amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ &amount_without_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ deposit_fee),
GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id),
GNUNET_PQ_query_param_uint64 (&deposit_shard),
@@ -72,7 +77,6 @@ TEH_PG_do_refund (
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
- /* Used in #postgres_do_refund() to refund a deposit. */
PREPARE (pg,
"call_refund",
"SELECT "
@@ -81,8 +85,7 @@ TEH_PG_do_refund (
",out_gone AS gone"
",out_conflict AS conflict"
" FROM exchange_do_refund"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
-
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_refund",
params,
diff --git a/src/exchangedb/pg_do_reserve_open.c b/src/exchangedb/pg_do_reserve_open.c
index 542d1f468..b15c96dd1 100644
--- a/src/exchangedb/pg_do_reserve_open.c
+++ b/src/exchangedb/pg_do_reserve_open.c
@@ -38,44 +38,64 @@ TEH_PG_do_reserve_open (
struct GNUNET_TIME_Timestamp now,
const struct TALER_Amount *open_fee,
bool *no_funds,
+ struct TALER_Amount *reserve_balance,
struct TALER_Amount *open_cost,
struct GNUNET_TIME_Timestamp *final_expiration)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_amount (total_paid),
- TALER_PQ_query_param_amount (reserve_payment),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ total_paid),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ reserve_payment),
GNUNET_PQ_query_param_uint32 (&min_purse_limit),
GNUNET_PQ_query_param_uint32 (&pg->def_purse_limit),
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
GNUNET_PQ_query_param_timestamp (&desired_expiration),
GNUNET_PQ_query_param_relative_time (&pg->legal_reserve_expiration_time),
GNUNET_PQ_query_param_timestamp (&now),
- TALER_PQ_query_param_amount (open_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ open_fee),
GNUNET_PQ_query_param_end
};
+ bool no_reserve = true;
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("out_open_cost",
+ TALER_PQ_result_spec_amount ("out_open_cost",
+ pg->currency,
open_cost),
+ TALER_PQ_result_spec_amount ("out_reserve_balance",
+ pg->currency,
+ reserve_balance),
GNUNET_PQ_result_spec_timestamp ("out_final_expiration",
final_expiration),
+ GNUNET_PQ_result_spec_bool ("out_no_reserve",
+ &no_reserve),
GNUNET_PQ_result_spec_bool ("out_no_funds",
no_funds),
GNUNET_PQ_result_spec_end
};
+ enum GNUNET_DB_QueryStatus qs;
PREPARE (pg,
"do_reserve_open",
"SELECT "
- " out_open_cost_val"
- ",out_open_cost_frac"
+ " out_open_cost"
",out_final_expiration"
",out_no_funds"
+ ",out_no_reserve"
+ ",out_reserve_balance"
" FROM exchange_do_reserve_open"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "do_reserve_open",
- params,
- rs);
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "do_reserve_open",
+ params,
+ rs);
+ if (qs <= 0)
+ return qs;
+ if (no_reserve)
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ return qs;
}
diff --git a/src/exchangedb/pg_do_reserve_open.h b/src/exchangedb/pg_do_reserve_open.h
index acf2d67ee..432f3f664 100644
--- a/src/exchangedb/pg_do_reserve_open.h
+++ b/src/exchangedb/pg_do_reserve_open.h
@@ -39,6 +39,7 @@
* @param now when did we the client initiate the action
* @param open_fee annual fee to be charged for the open operation by the exchange
* @param[out] no_funds set to true if reserve balance is insufficient
+ * @param[out] reserve_balance set to the original reserve balance (at the start of this transaction)
* @param[out] open_cost set to the actual cost
* @param[out] final_expiration when will the reserve expire now
* @return transaction status code
@@ -55,6 +56,7 @@ TEH_PG_do_reserve_open (
struct GNUNET_TIME_Timestamp now,
const struct TALER_Amount *open_fee,
bool *no_funds,
+ struct TALER_Amount *reserve_balance,
struct TALER_Amount *open_cost,
struct GNUNET_TIME_Timestamp *final_expiration);
diff --git a/src/exchangedb/pg_do_reserve_purse.c b/src/exchangedb/pg_do_reserve_purse.c
index b08594175..e03e23fec 100644
--- a/src/exchangedb/pg_do_reserve_purse.c
+++ b/src/exchangedb/pg_do_reserve_purse.c
@@ -74,9 +74,10 @@ TEH_PG_do_reserve_purse (
GNUNET_PQ_query_param_timestamp (&reserve_gc),
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
GNUNET_PQ_query_param_bool (NULL == purse_fee),
- TALER_PQ_query_param_amount (NULL == purse_fee
- ? &zero_fee
- : purse_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ NULL == purse_fee
+ ? &zero_fee
+ : purse_fee),
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_end
@@ -111,7 +112,7 @@ TEH_PG_do_reserve_purse (
",out_no_reserve AS no_reserve"
",out_conflict AS conflict"
" FROM exchange_do_reserve_purse"
- " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);");
+ " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_reserve_purse",
diff --git a/src/exchangedb/pg_do_withdraw.c b/src/exchangedb/pg_do_withdraw.c
deleted file mode 100644
index 87e4dd1d0..000000000
--- a/src/exchangedb/pg_do_withdraw.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_do_withdraw.c
- * @brief Implementation of the do_withdraw function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_do_withdraw.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_do_withdraw (
- void *cls,
- const struct TALER_CsNonce *nonce,
- const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
- struct GNUNET_TIME_Timestamp now,
- bool *found,
- bool *balance_ok,
- bool *nonce_ok,
- uint64_t *ruuid)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp gc;
- struct GNUNET_PQ_QueryParam params[] = {
- NULL == nonce
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_auto_from_type (nonce),
- TALER_PQ_query_param_amount (&collectable->amount_with_fee),
- GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
- GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
- GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
- GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
- TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_timestamp (&gc),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("reserve_found",
- found),
- GNUNET_PQ_result_spec_bool ("balance_ok",
- balance_ok),
- GNUNET_PQ_result_spec_bool ("nonce_ok",
- nonce_ok),
- GNUNET_PQ_result_spec_uint64 ("ruuid",
- ruuid),
- GNUNET_PQ_result_spec_end
- };
-
- PREPARE (pg,
- "call_withdraw",
- "SELECT "
- " reserve_found"
- ",balance_ok"
- ",nonce_ok"
- ",ruuid"
- " FROM exchange_do_withdraw"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
- gc = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (now.abs_time,
- pg->legal_reserve_expiration_time));
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "call_withdraw",
- params,
- rs);
-}
-
-
diff --git a/src/exchangedb/pg_do_withdraw.h b/src/exchangedb/pg_do_withdraw.h
deleted file mode 100644
index 406785c42..000000000
--- a/src/exchangedb/pg_do_withdraw.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_do_withdraw.h
- * @brief implementation of the do_withdraw function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_DO_WITHDRAW_H
-#define PG_DO_WITHDRAW_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-
-/**
- * Perform withdraw operation, checking for sufficient balance
- * and possibly persisting the withdrawal details.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param nonce client-contributed input for CS denominations that must be checked for idempotency, or NULL for non-CS withdrawals
- * @param[in,out] collectable corresponding collectable coin (blind signature) if a coin is found; possibly updated if a (different) signature exists already
- * @param now current time (rounded)
- * @param[out] found set to true if the reserve was found
- * @param[out] balance_ok set to true if the balance was sufficient
- * @param[out] nonce_ok set to false if the nonce was reused
- * @param[out] ruuid set to the reserve's UUID (reserves table row)
- * @return query execution status
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_do_withdraw (
- void *cls,
- const struct TALER_CsNonce *nonce,
- const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
- struct GNUNET_TIME_Timestamp now,
- bool *found,
- bool *balance_ok,
- bool *nonce_ok,
- uint64_t *ruuid);
-
-#endif
diff --git a/src/exchangedb/pg_drain_kyc_alert.c b/src/exchangedb/pg_drain_kyc_alert.c
index d635d95e9..4388334e9 100644
--- a/src/exchangedb/pg_drain_kyc_alert.c
+++ b/src/exchangedb/pg_drain_kyc_alert.c
@@ -28,8 +28,8 @@
enum GNUNET_DB_QueryStatus
TEH_PG_drain_kyc_alert (void *cls,
- uint32_t trigger_type,
- struct TALER_PaytoHashP *h_payto)
+ uint32_t trigger_type,
+ struct TALER_PaytoHashP *h_payto)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
diff --git a/src/exchangedb/pg_drain_kyc_alert.h b/src/exchangedb/pg_drain_kyc_alert.h
index bfaf04892..7425f472d 100644
--- a/src/exchangedb/pg_drain_kyc_alert.h
+++ b/src/exchangedb/pg_drain_kyc_alert.h
@@ -34,7 +34,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_drain_kyc_alert (void *cls,
- uint32_t trigger_type,
+ uint32_t trigger_type,
struct TALER_PaytoHashP *h_payto);
#endif
diff --git a/src/exchangedb/pg_ensure_coin_known.c b/src/exchangedb/pg_ensure_coin_known.c
index 7ad37bf1d..307b8df52 100644
--- a/src/exchangedb/pg_ensure_coin_known.c
+++ b/src/exchangedb/pg_ensure_coin_known.c
@@ -21,6 +21,7 @@
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
+#include "taler_exchangedb_plugin.h"
#include "taler_pq_lib.h"
#include "pg_ensure_coin_known.h"
#include "pg_helper.h"
@@ -28,10 +29,10 @@
enum TALER_EXCHANGEDB_CoinKnownStatus
TEH_PG_ensure_coin_known (void *cls,
- const struct TALER_CoinPublicInfo *coin,
- uint64_t *known_coin_id,
- struct TALER_DenominationHashP *denom_hash,
- struct TALER_AgeCommitmentHash *h_age_commitment)
+ const struct TALER_CoinPublicInfo *coin,
+ uint64_t *known_coin_id,
+ struct TALER_DenominationHashP *denom_hash,
+ struct TALER_AgeCommitmentHash *h_age_commitment)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs;
@@ -41,7 +42,9 @@ TEH_PG_ensure_coin_known (void *cls,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
GNUNET_PQ_query_param_auto_from_type (&coin->denom_pub_hash),
- GNUNET_PQ_query_param_auto_from_type (&coin->h_age_commitment),
+ coin->no_age_commitment
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (&coin->h_age_commitment),
TALER_PQ_query_param_denom_sig (&coin->denom_sig),
GNUNET_PQ_query_param_end
};
@@ -60,9 +63,8 @@ TEH_PG_ensure_coin_known (void *cls,
&is_age_hash_null),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_insert_known_coin() to store the denomination public
- key and signature for a coin known to the exchange.
+ /*
See also:
https://stackoverflow.com/questions/34708509/how-to-use-returning-with-on-conflict-in-postgresql/37543015#37543015
*/
@@ -70,13 +72,11 @@ TEH_PG_ensure_coin_known (void *cls,
"insert_known_coin",
"WITH dd"
" (denominations_serial"
- " ,coin_val"
- " ,coin_frac"
+ " ,coin"
" ) AS ("
" SELECT "
" denominations_serial"
- " ,coin_val"
- " ,coin_frac"
+ " ,coin"
" FROM denominations"
" WHERE denom_pub_hash=$2"
" ), input_rows"
@@ -88,15 +88,13 @@ TEH_PG_ensure_coin_known (void *cls,
" ,denominations_serial"
" ,age_commitment_hash"
" ,denom_sig"
- " ,remaining_val"
- " ,remaining_frac"
+ " ,remaining"
" ) SELECT "
" $1"
" ,denominations_serial"
" ,$3"
" ,$4"
- " ,coin_val"
- " ,coin_frac"
+ " ,coin"
" FROM dd"
" ON CONFLICT DO NOTHING" /* CONFLICT on (coin_pub) */
" RETURNING "
@@ -146,13 +144,25 @@ TEH_PG_ensure_coin_known (void *cls,
return TALER_EXCHANGEDB_CKS_DENOM_CONFLICT;
}
- if ( (! is_age_hash_null) &&
- (0 != GNUNET_memcmp (h_age_commitment,
- &coin->h_age_commitment)) )
+ if (is_age_hash_null != coin->no_age_commitment)
+ {
+ if (is_age_hash_null)
+ {
+ GNUNET_break_op (0);
+ return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NULL;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NON_NULL;
+ }
+ }
+ else if ( (! is_age_hash_null) &&
+ (0 != GNUNET_memcmp (h_age_commitment,
+ &coin->h_age_commitment)) )
{
- GNUNET_break (GNUNET_is_zero (h_age_commitment));
GNUNET_break_op (0);
- return TALER_EXCHANGEDB_CKS_AGE_CONFLICT;
+ return TALER_EXCHANGEDB_CKS_AGE_CONFLICT_VALUE_DIFFERS;
}
return TALER_EXCHANGEDB_CKS_PRESENT;
diff --git a/src/exchangedb/pg_ensure_coin_known.h b/src/exchangedb/pg_ensure_coin_known.h
index 76581d4b7..68c101735 100644
--- a/src/exchangedb/pg_ensure_coin_known.h
+++ b/src/exchangedb/pg_ensure_coin_known.h
@@ -37,9 +37,9 @@
*/
enum TALER_EXCHANGEDB_CoinKnownStatus
TEH_PG_ensure_coin_known (void *cls,
- const struct TALER_CoinPublicInfo *coin,
- uint64_t *known_coin_id,
- struct TALER_DenominationHashP *denom_hash,
+ const struct TALER_CoinPublicInfo *coin,
+ uint64_t *known_coin_id,
+ struct TALER_DenominationHashP *denom_hash,
struct TALER_AgeCommitmentHash *h_age_commitment);
#endif
diff --git a/src/exchangedb/pg_event_listen.c b/src/exchangedb/pg_event_listen.c
index c557ed3c5..6e1d32843 100644
--- a/src/exchangedb/pg_event_listen.c
+++ b/src/exchangedb/pg_event_listen.c
@@ -38,10 +38,10 @@
*/
struct GNUNET_DB_EventHandler *
TEH_PG_event_listen (void *cls,
- struct GNUNET_TIME_Relative timeout,
- const struct GNUNET_DB_EventHeaderP *es,
- GNUNET_DB_EventCallback cb,
- void *cb_cls)
+ struct GNUNET_TIME_Relative timeout,
+ const struct GNUNET_DB_EventHeaderP *es,
+ GNUNET_DB_EventCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
diff --git a/src/exchangedb/pg_event_listen.h b/src/exchangedb/pg_event_listen.h
index 1be140776..7e1e83a0e 100644
--- a/src/exchangedb/pg_event_listen.h
+++ b/src/exchangedb/pg_event_listen.h
@@ -37,9 +37,9 @@
*/
struct GNUNET_DB_EventHandler *
TEH_PG_event_listen (void *cls,
- struct GNUNET_TIME_Relative timeout,
- const struct GNUNET_DB_EventHeaderP *es,
- GNUNET_DB_EventCallback cb,
+ struct GNUNET_TIME_Relative timeout,
+ const struct GNUNET_DB_EventHeaderP *es,
+ GNUNET_DB_EventCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_event_listen_cancel.c b/src/exchangedb/pg_event_listen_cancel.c
index 5d65827c2..9d776684d 100644
--- a/src/exchangedb/pg_event_listen_cancel.c
+++ b/src/exchangedb/pg_event_listen_cancel.c
@@ -26,10 +26,9 @@
#include "pg_helper.h"
-
void
TEH_PG_event_listen_cancel (void *cls,
- struct GNUNET_DB_EventHandler *eh)
+ struct GNUNET_DB_EventHandler *eh)
{
(void) cls;
diff --git a/src/exchangedb/pg_event_notify.c b/src/exchangedb/pg_event_notify.c
index 577f4acb8..188855775 100644
--- a/src/exchangedb/pg_event_notify.c
+++ b/src/exchangedb/pg_event_notify.c
@@ -28,9 +28,9 @@
void
TEH_PG_event_notify (void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- const void *extra,
- size_t extra_size)
+ const struct GNUNET_DB_EventHeaderP *es,
+ const void *extra,
+ size_t extra_size)
{
struct PostgresClosure *pg = cls;
diff --git a/src/exchangedb/pg_event_notify.h b/src/exchangedb/pg_event_notify.h
index 3b937cbab..85069659b 100644
--- a/src/exchangedb/pg_event_notify.h
+++ b/src/exchangedb/pg_event_notify.h
@@ -35,8 +35,8 @@
*/
void
TEH_PG_event_notify (void *cls,
- const struct GNUNET_DB_EventHeaderP *es,
- const void *extra,
+ const struct GNUNET_DB_EventHeaderP *es,
+ const void *extra,
size_t extra_size);
#endif
diff --git a/src/exchangedb/pg_find_aggregation_transient.c b/src/exchangedb/pg_find_aggregation_transient.c
index a5f367b5f..b931188a8 100644
--- a/src/exchangedb/pg_find_aggregation_transient.c
+++ b/src/exchangedb/pg_find_aggregation_transient.c
@@ -128,12 +128,11 @@ TEH_PG_find_aggregation_transient (
.pg = pg,
.status = GNUNET_OK
};
- /* Used in #postgres_find_aggregation_transient() */
+
PREPARE (pg,
"find_transient_aggregations",
"SELECT"
- " amount_val"
- " ,amount_frac"
+ " amount"
" ,wtid_raw"
" ,merchant_pub"
" ,payto_uri"
diff --git a/src/exchangedb/pg_gc.h b/src/exchangedb/pg_gc.h
index 9e6ffbc3d..803581488 100644
--- a/src/exchangedb/pg_gc.h
+++ b/src/exchangedb/pg_gc.h
@@ -35,4 +35,5 @@
*/
enum GNUNET_GenericReturnValue
TEH_PG_gc (void *cls);
+
#endif
diff --git a/src/exchangedb/pg_get_age_withdraw.c b/src/exchangedb/pg_get_age_withdraw.c
new file mode 100644
index 000000000..ea4d3b909
--- /dev/null
+++ b/src/exchangedb/pg_get_age_withdraw.c
@@ -0,0 +1,119 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_age_withdraw.c
+ * @brief Implementation of the get_age_withdraw function for Postgres
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_get_age_withdraw.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_age_withdraw (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_AgeWithdrawCommitmentHashP *ach,
+ struct TALER_EXCHANGEDB_AgeWithdraw *aw)
+{
+ enum GNUNET_DB_QueryStatus ret;
+ struct PostgresClosure *pg = cls;
+ size_t num_sigs;
+ size_t num_hashes;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (ach),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_commitment",
+ &aw->h_commitment),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
+ &aw->reserve_sig),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &aw->reserve_pub),
+ GNUNET_PQ_result_spec_uint16 ("max_age",
+ &aw->max_age),
+ TALER_PQ_result_spec_amount ("amount_with_fee",
+ pg->currency,
+ &aw->amount_with_fee),
+ GNUNET_PQ_result_spec_uint16 ("noreveal_index",
+ &aw->noreveal_index),
+ TALER_PQ_result_spec_array_blinded_coin_hash (
+ pg->conn,
+ "h_blind_evs",
+ &aw->num_coins,
+ &aw->h_coin_evs),
+ TALER_PQ_result_spec_array_blinded_denom_sig (
+ pg->conn,
+ "denom_sigs",
+ &num_sigs,
+ &aw->denom_sigs),
+ TALER_PQ_result_spec_array_denom_hash (
+ pg->conn,
+ "denom_pub_hashes",
+ &num_hashes,
+ &aw->denom_pub_hashes),
+ GNUNET_PQ_result_spec_end
+ };
+
+ PREPARE (pg,
+ "get_age_withdraw",
+ "SELECT"
+ " h_commitment"
+ ",reserve_sig"
+ ",reserve_pub"
+ ",max_age"
+ ",amount_with_fee"
+ ",noreveal_index"
+ ",h_blind_evs"
+ ",denom_sigs"
+ ",ARRAY("
+ " SELECT denominations.denom_pub_hash FROM ("
+ " SELECT UNNEST(denom_serials) AS id,"
+ " generate_subscripts(denom_serials, 1) AS nr" /* for order */
+ " ) AS denoms"
+ " LEFT JOIN denominations ON denominations.denominations_serial=denoms.id"
+ ") AS denom_pub_hashes"
+ " FROM age_withdraw"
+ " WHERE reserve_pub=$1 and h_commitment=$2;");
+
+ ret = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_age_withdraw",
+ params,
+ rs);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ret)
+ return ret;
+
+ if ((aw->num_coins != num_sigs) ||
+ (aw->num_coins != num_hashes))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "got inconsistent number of entries from DB: "
+ "num_coins=%ld, num_sigs=%ld, num_hashes=%ld\n",
+ aw->num_coins,
+ num_sigs,
+ num_hashes);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ return ret;
+}
diff --git a/src/exchangedb/pg_get_age_withdraw.h b/src/exchangedb/pg_get_age_withdraw.h
new file mode 100644
index 000000000..2257aa43c
--- /dev/null
+++ b/src/exchangedb/pg_get_age_withdraw.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_age_withdraw.h
+ * @brief implementation of the get_age_withdraw function for Postgres
+ * @author Özgür KESIM
+ */
+#ifndef PG_GET_AGE_WITHDRAW_H
+#define PG_GET_AGE_WITHDRAW_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Locate the response for a age-withdraw request under a hash that uniquely
+ * identifies the age-withdraw operation. Used to ensure idempotency of the
+ * request.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param reserve_pub public key of the reserve for which the age-withdraw request is made
+ * @param ach hash that uniquely identifies the age-withdraw operation
+ * @param[out] aw corresponding details of the previous age-withdraw request if an entry was found
+ * @return statement execution status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_age_withdraw (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_AgeWithdrawCommitmentHashP *ach,
+ struct TALER_EXCHANGEDB_AgeWithdraw *aw);
+#endif
diff --git a/src/exchangedb/pg_get_coin_denomination.c b/src/exchangedb/pg_get_coin_denomination.c
index e82b86aa9..9f9256f6f 100644
--- a/src/exchangedb/pg_get_coin_denomination.c
+++ b/src/exchangedb/pg_get_coin_denomination.c
@@ -49,9 +49,9 @@ TEH_PG_get_coin_denomination (
"Getting coin denomination of coin %s\n",
TALER_B2S (coin_pub));
- /* Used in #postgres_get_coin_denomination() to fetch
- the denomination public key hash for
- a coin known to the exchange. */
+ /* Used in #postgres_get_coin_denomination() to fetch
+ the denomination public key hash for
+ a coin known to the exchange. */
PREPARE (pg,
"get_coin_denomination",
"SELECT"
@@ -67,5 +67,3 @@ TEH_PG_get_coin_denomination (
params,
rs);
}
-
-
diff --git a/src/exchangedb/pg_get_coin_transactions.c b/src/exchangedb/pg_get_coin_transactions.c
index f24c9be4a..fef33a486 100644
--- a/src/exchangedb/pg_get_coin_transactions.c
+++ b/src/exchangedb/pg_get_coin_transactions.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -21,11 +21,21 @@
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
+#include "taler_exchangedb_plugin.h"
#include "taler_pq_lib.h"
#include "pg_get_coin_transactions.h"
#include "pg_helper.h"
+#include "pg_start_read_committed.h"
+#include "pg_commit.h"
+#include "pg_rollback.h"
#include "plugin_exchangedb_common.h"
+/**
+ * How often do we re-try when encountering DB serialization issues?
+ * (We are read-only, so can only happen due to concurrent insert,
+ * which should be very rare.)
+ */
+#define RETRIES 3
/**
* Closure for callbacks called from #postgres_get_coin_transactions()
@@ -43,11 +53,6 @@ struct CoinHistoryContext
const struct TALER_CoinSpendPublicKeyP *coin_pub;
/**
- * Closure for all callbacks of this database plugin.
- */
- void *db_cls;
-
- /**
* Plugin context.
*/
struct PostgresClosure *pg;
@@ -57,10 +62,6 @@ struct CoinHistoryContext
*/
bool failed;
- /**
- * Set to 'true' if we found a deposit or melt (for invariant check).
- */
- bool have_deposit_or_melt;
};
@@ -86,7 +87,6 @@ add_coin_deposit (void *cls,
struct TALER_EXCHANGEDB_TransactionList *tl;
uint64_t serial_id;
- chc->have_deposit_or_melt = true;
deposit = GNUNET_new (struct TALER_EXCHANGEDB_DepositListEntry);
{
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -100,6 +100,10 @@ add_coin_deposit (void *cls,
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&deposit->h_age_commitment),
&deposit->no_age_commitment),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("wallet_data_hash",
+ &deposit->wallet_data_hash),
+ &deposit->no_wallet_data_hash),
GNUNET_PQ_result_spec_timestamp ("wallet_timestamp",
&deposit->timestamp),
GNUNET_PQ_result_spec_timestamp ("refund_deadline",
@@ -116,7 +120,7 @@ add_coin_deposit (void *cls,
&deposit->receiver_wire_account),
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
&deposit->csig),
- GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
+ GNUNET_PQ_result_spec_uint64 ("coin_deposit_serial_id",
&serial_id),
GNUNET_PQ_result_spec_auto_from_type ("done",
&deposit->done),
@@ -166,7 +170,6 @@ add_coin_purse_deposit (void *cls,
struct TALER_EXCHANGEDB_TransactionList *tl;
uint64_t serial_id;
- chc->have_deposit_or_melt = true;
deposit = GNUNET_new (struct TALER_EXCHANGEDB_PurseDepositListEntry);
{
bool not_finished;
@@ -185,8 +188,10 @@ add_coin_purse_deposit (void *cls,
NULL),
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
&deposit->coin_sig),
- GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
- &deposit->h_age_commitment),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
+ &deposit->h_age_commitment),
+ &deposit->no_age_commitment),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_bool ("refunded",
&deposit->refunded),
@@ -240,7 +245,6 @@ add_coin_melt (void *cls,
struct TALER_EXCHANGEDB_TransactionList *tl;
uint64_t serial_id;
- chc->have_deposit_or_melt = true;
melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry);
{
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -663,6 +667,11 @@ add_coin_reserve_open (void *cls,
struct Work
{
/**
+ * Name of the table.
+ */
+ const char *table;
+
+ /**
* SQL prepared statement name.
*/
const char *statement;
@@ -674,92 +683,218 @@ struct Work
};
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_coin_transactions (
- void *cls,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- struct TALER_EXCHANGEDB_TransactionList **tlp)
+/**
+ * We found a coin history entry. Lookup details
+ * from the respective table and store in @a cls.
+ *
+ * @param[in,out] cls a `struct CoinHistoryContext`
+ * @param result a coin history entry result set
+ * @param num_results total number of results in @a results
+ */
+static void
+handle_history_entry (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
+ struct CoinHistoryContext *chc = cls;
+ struct PostgresClosure *pg = chc->pg;
static const struct Work work[] = {
- /** #TALER_EXCHANGEDB_TT_DEPOSIT */
- { "get_deposit_with_coin_pub",
+ [TALER_EXCHANGEDB_TT_DEPOSIT] =
+ { "coin_deposits",
+ "get_deposit_with_coin_pub",
&add_coin_deposit },
- /** #TALER_EXCHANGEDB_TT_MELT */
- { "get_refresh_session_by_coin",
+ [TALER_EXCHANGEDB_TT_MELT] =
+ { "refresh_commitments",
+ "get_refresh_session_by_coin",
&add_coin_melt },
- /** #TALER_EXCHANGEDB_TT_PURSE_DEPOSIT */
- { "get_purse_deposit_by_coin_pub",
+ [TALER_EXCHANGEDB_TT_PURSE_DEPOSIT] =
+ { "purse_deposits",
+ "get_purse_deposit_by_coin_pub",
&add_coin_purse_deposit },
- /** #TALER_EXCHANGEDB_TT_PURSE_REFUND */
- { "get_purse_decision_by_coin_pub",
+ [TALER_EXCHANGEDB_TT_PURSE_REFUND] =
+ { "purse_decision",
+ "get_purse_decision_by_coin_pub",
&add_coin_purse_decision },
- /** #TALER_EXCHANGEDB_TT_REFUND */
- { "get_refunds_by_coin",
+ [TALER_EXCHANGEDB_TT_REFUND] =
+ { "refunds",
+ "get_refunds_by_coin",
&add_coin_refund },
- /** #TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP */
- { "recoup_by_old_coin",
+ [TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP] =
+ { "recoup_refresh::OLD",
+ "recoup_by_old_coin",
&add_old_coin_recoup },
- /** #TALER_EXCHANGEDB_TT_RECOUP */
- { "recoup_by_coin",
+ [TALER_EXCHANGEDB_TT_RECOUP] =
+ { "recoup",
+ "recoup_by_coin",
&add_coin_recoup },
- /** #TALER_EXCHANGEDB_TT_RECOUP_REFRESH */
- { "recoup_by_refreshed_coin",
+ [TALER_EXCHANGEDB_TT_RECOUP_REFRESH] =
+ { "recoup_refresh::NEW",
+ "recoup_by_refreshed_coin",
&add_coin_recoup_refresh },
- /** #TALER_EXCHANGEDB_TT_RESERVE_OPEN */
- { "reserve_open_by_coin",
+ [TALER_EXCHANGEDB_TT_RESERVE_OPEN] =
+ { "reserves_open_deposits",
+ "reserve_open_by_coin",
&add_coin_reserve_open },
- { NULL, NULL }
+ { NULL, NULL, NULL }
+ };
+ char *table_name;
+ uint64_t serial_id;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("table_name",
+ &table_name),
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &serial_id),
+ GNUNET_PQ_result_spec_end
};
struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (chc->coin_pub),
+ GNUNET_PQ_query_param_uint64 (&serial_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ enum GNUNET_DB_QueryStatus qs;
+ bool found = false;
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ chc->failed = true;
+ return;
+ }
+
+ for (unsigned int s = 0;
+ NULL != work[s].statement;
+ s++)
+ {
+ if (0 != strcmp (table_name,
+ work[s].table))
+ continue;
+ found = true;
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ work[s].statement,
+ params,
+ work[s].cb,
+ chc);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Coin %s had %d transactions at %llu in table %s\n",
+ TALER_B2S (chc->coin_pub),
+ (int) qs,
+ (unsigned long long) serial_id,
+ table_name);
+ if (0 >= qs)
+ chc->failed = true;
+ break;
+ }
+ if (! found)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Coin history includes unsupported table `%s`\n",
+ table_name);
+ chc->failed = true;
+ }
+ GNUNET_PQ_cleanup_result (rs);
+ if (chc->failed)
+ break;
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_coin_transactions (
+ void *cls,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t start_off,
+ uint64_t etag_in,
+ uint64_t *etag_out,
+ struct TALER_Amount *balance,
+ struct TALER_DenominationHashP *h_denom_pub,
+ struct TALER_EXCHANGEDB_TransactionList **tlp)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_end
};
- enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam lparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_uint64 (&start_off),
+ GNUNET_PQ_query_param_end
+ };
struct CoinHistoryContext chc = {
.head = NULL,
.coin_pub = coin_pub,
- .pg = pg,
- .db_cls = cls
+ .pg = pg
};
+ *tlp = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Getting transactions for coin %s\n",
+ TALER_B2S (coin_pub));
+ PREPARE (pg,
+ "get_coin_history_etag_balance",
+ "SELECT"
+ " ch.coin_history_serial_id"
+ ",kc.remaining"
+ ",denom.denom_pub_hash"
+ " FROM coin_history ch"
+ " JOIN known_coins kc"
+ " USING (coin_pub)"
+ " JOIN denominations denom"
+ " USING (denominations_serial)"
+ " WHERE coin_pub=$1"
+ " ORDER BY coin_history_serial_id DESC"
+ " LIMIT 1;");
+ PREPARE (pg,
+ "get_coin_history",
+ "SELECT"
+ " table_name"
+ ",serial_id"
+ " FROM coin_history"
+ " WHERE coin_pub=$1"
+ " AND coin_history_serial_id > $2"
+ " ORDER BY coin_history_serial_id DESC;");
PREPARE (pg,
"get_deposit_with_coin_pub",
"SELECT"
- " dep.amount_with_fee_val"
- ",dep.amount_with_fee_frac"
- ",denoms.fee_deposit_val"
- ",denoms.fee_deposit_frac"
+ " cdep.amount_with_fee"
+ ",denoms.fee_deposit"
",denoms.denom_pub_hash"
",kc.age_commitment_hash"
- ",dep.wallet_timestamp"
- ",dep.refund_deadline"
- ",dep.wire_deadline"
- ",dep.merchant_pub"
- ",dep.h_contract_terms"
- ",dep.wire_salt"
+ ",bdep.wallet_timestamp"
+ ",bdep.refund_deadline"
+ ",bdep.wire_deadline"
+ ",bdep.merchant_pub"
+ ",bdep.h_contract_terms"
+ ",bdep.wallet_data_hash"
+ ",bdep.wire_salt"
",wt.payto_uri"
- ",dep.coin_sig"
- ",dep.deposit_serial_id"
- ",dep.done"
- " FROM deposits dep"
- " JOIN wire_targets wt"
- " USING (wire_target_h_payto)"
- " JOIN known_coins kc"
- " ON (kc.coin_pub = dep.coin_pub)"
- " JOIN denominations denoms"
- " USING (denominations_serial)"
- " WHERE dep.coin_pub=$1;");
+ ",cdep.coin_sig"
+ ",cdep.coin_deposit_serial_id"
+ ",bdep.done"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
+ " JOIN wire_targets wt"
+ " USING (wire_target_h_payto)"
+ " JOIN known_coins kc"
+ " ON (kc.coin_pub = cdep.coin_pub)"
+ " JOIN denominations denoms"
+ " USING (denominations_serial)"
+ " WHERE cdep.coin_pub=$1"
+ " AND cdep.coin_deposit_serial_id=$2;");
PREPARE (pg,
"get_refresh_session_by_coin",
"SELECT"
" rc"
",old_coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",denoms.denom_pub_hash"
- ",denoms.fee_refresh_val"
- ",denoms.fee_refresh_frac"
+ ",denoms.fee_refresh"
",kc.age_commitment_hash"
",melt_serial_id"
" FROM refresh_commitments"
@@ -767,15 +902,14 @@ TEH_PG_get_coin_transactions (
" ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
" JOIN denominations denoms"
" USING (denominations_serial)"
- " WHERE old_coin_pub=$1;");
+ " WHERE old_coin_pub=$1"
+ " AND melt_serial_id=$2;");
PREPARE (pg,
"get_purse_deposit_by_coin_pub",
"SELECT"
" partner_base_url"
- ",pd.amount_with_fee_val"
- ",pd.amount_with_fee_frac"
- ",denoms.fee_deposit_val"
- ",denoms.fee_deposit_frac"
+ ",pd.amount_with_fee"
+ ",denoms.fee_deposit"
",pd.purse_pub"
",kc.age_commitment_hash"
",pd.coin_sig"
@@ -792,110 +926,104 @@ TEH_PG_get_coin_transactions (
" ON (pd.coin_pub = kc.coin_pub)"
" JOIN denominations denoms"
" USING (denominations_serial)"
- // FIXME: use to-be-created materialized index
- // on coin_pub (query crosses partitions!)
- " WHERE pd.coin_pub=$1;");
- PREPARE (pg,
- "get_refunds_by_coin",
- "SELECT"
- " dep.merchant_pub"
- ",ref.merchant_sig"
- ",dep.h_contract_terms"
- ",ref.rtransaction_id"
- ",ref.amount_with_fee_val"
- ",ref.amount_with_fee_frac"
- ",denom.fee_refund_val "
- ",denom.fee_refund_frac "
- ",ref.refund_serial_id"
- " FROM refunds ref"
- " JOIN deposits dep"
- " ON (ref.coin_pub = dep.coin_pub AND ref.deposit_serial_id = dep.deposit_serial_id)"
- " JOIN known_coins kc"
- " ON (ref.coin_pub = kc.coin_pub)"
- " JOIN denominations denom"
- " USING (denominations_serial)"
- " WHERE ref.coin_pub=$1;");
+ " WHERE pd.purse_deposit_serial_id=$2"
+ " AND pd.coin_pub=$1;");
PREPARE (pg,
"get_purse_decision_by_coin_pub",
"SELECT"
" pdes.purse_pub"
- ",pd.amount_with_fee_val"
- ",pd.amount_with_fee_frac"
- ",denom.fee_refund_val "
- ",denom.fee_refund_frac "
+ ",pd.amount_with_fee"
+ ",denom.fee_refund"
",pdes.purse_decision_serial_id"
- " FROM purse_deposits pd"
- " JOIN purse_decision pdes"
+ " FROM purse_decision pdes"
+ " JOIN purse_deposits pd"
" USING (purse_pub)"
" JOIN known_coins kc"
" ON (pd.coin_pub = kc.coin_pub)"
" JOIN denominations denom"
" USING (denominations_serial)"
" WHERE pd.coin_pub=$1"
+ " AND pdes.purse_decision_serial_id=$2"
" AND pdes.refunded;");
PREPARE (pg,
+ "get_refunds_by_coin",
+ "SELECT"
+ " bdep.merchant_pub"
+ ",ref.merchant_sig"
+ ",bdep.h_contract_terms"
+ ",ref.rtransaction_id"
+ ",ref.amount_with_fee"
+ ",denom.fee_refund"
+ ",ref.refund_serial_id"
+ " FROM refunds ref"
+ " JOIN coin_deposits cdep"
+ " ON (ref.coin_pub = cdep.coin_pub AND ref.batch_deposit_serial_id = cdep.batch_deposit_serial_id)"
+ " JOIN batch_deposits bdep"
+ " ON (ref.batch_deposit_serial_id = bdep.batch_deposit_serial_id)"
+ " JOIN known_coins kc"
+ " ON (ref.coin_pub = kc.coin_pub)"
+ " JOIN denominations denom"
+ " USING (denominations_serial)"
+ " WHERE ref.coin_pub=$1"
+ " AND ref.refund_serial_id=$2;");
+ PREPARE (pg,
"recoup_by_old_coin",
"SELECT"
" coins.coin_pub"
- ",coin_sig"
- ",coin_blind"
- ",amount_val"
- ",amount_frac"
- ",recoup_timestamp"
+ ",rr.coin_sig"
+ ",rr.coin_blind"
+ ",rr.amount"
+ ",rr.recoup_timestamp"
",denoms.denom_pub_hash"
",coins.denom_sig"
- ",recoup_refresh_uuid"
- " FROM recoup_refresh"
+ ",rr.recoup_refresh_uuid"
+ " FROM recoup_refresh rr"
" JOIN known_coins coins"
" USING (coin_pub)"
" JOIN denominations denoms"
" USING (denominations_serial)"
- " WHERE rrc_serial IN"
+ " WHERE recoup_refresh_uuid=$2"
+ " AND rrc_serial IN"
" (SELECT rrc.rrc_serial"
- " FROM refresh_commitments"
- " JOIN refresh_revealed_coins rrc"
- " USING (melt_serial_id)"
- " WHERE old_coin_pub=$1);");
+ " FROM refresh_commitments melt"
+ " JOIN refresh_revealed_coins rrc"
+ " USING (melt_serial_id)"
+ " WHERE melt.old_coin_pub=$1);");
PREPARE (pg,
"recoup_by_coin",
"SELECT"
- " reserves.reserve_pub"
+ " res.reserve_pub"
",denoms.denom_pub_hash"
- ",coin_sig"
- ",coin_blind"
- ",amount_val"
- ",amount_frac"
- ",recoup_timestamp"
- ",recoup_uuid"
+ ",rcp.coin_sig"
+ ",rcp.coin_blind"
+ ",rcp.amount"
+ ",rcp.recoup_timestamp"
+ ",rcp.recoup_uuid"
" FROM recoup rcp"
- /* NOTE: suboptimal JOIN follows: crosses shards!
- Could theoretically be improved via a materialized
- index. But likely not worth it (query is rare and
- number of reserve shards might be limited) */
" JOIN reserves_out ro"
" USING (reserve_out_serial_id)"
- " JOIN reserves"
+ " JOIN reserves res"
" USING (reserve_uuid)"
" JOIN known_coins coins"
" USING (coin_pub)"
" JOIN denominations denoms"
" ON (denoms.denominations_serial = coins.denominations_serial)"
- " WHERE coins.coin_pub=$1;");
+ " WHERE rcp.recoup_uuid=$2"
+ " AND coins.coin_pub=$1;");
/* Used in #postgres_get_coin_transactions() to obtain recoup transactions
for a refreshed coin */
PREPARE (pg,
"recoup_by_refreshed_coin",
"SELECT"
" old_coins.coin_pub AS old_coin_pub"
- ",coin_sig"
- ",coin_blind"
- ",amount_val"
- ",amount_frac"
- ",recoup_timestamp"
+ ",rr.coin_sig"
+ ",rr.coin_blind"
+ ",rr.amount"
+ ",rr.recoup_timestamp"
",denoms.denom_pub_hash"
",coins.denom_sig"
",recoup_refresh_uuid"
- " FROM recoup_refresh"
+ " FROM recoup_refresh rr"
" JOIN refresh_revealed_coins rrc"
" USING (rrc_serial)"
" JOIN refresh_commitments rfc"
@@ -903,49 +1031,114 @@ TEH_PG_get_coin_transactions (
" JOIN known_coins old_coins"
" ON (rfc.old_coin_pub = old_coins.coin_pub)"
" JOIN known_coins coins"
- " ON (recoup_refresh.coin_pub = coins.coin_pub)"
+ " ON (rr.coin_pub = coins.coin_pub)"
" JOIN denominations denoms"
" ON (denoms.denominations_serial = coins.denominations_serial)"
- " WHERE coins.coin_pub=$1;");
+ " WHERE rr.recoup_refresh_uuid=$2"
+ " AND coins.coin_pub=$1;");
PREPARE (pg,
"reserve_open_by_coin",
"SELECT"
" reserve_open_deposit_uuid"
",coin_sig"
",reserve_sig"
- ",contribution_val"
- ",contribution_frac"
+ ",contribution"
" FROM reserves_open_deposits"
- " WHERE coin_pub=$1;");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Getting transactions for coin %s\n",
- TALER_B2S (coin_pub));
- for (unsigned int i = 0; NULL != work[i].statement; i++)
+ " WHERE coin_pub=$1"
+ " AND reserve_open_deposit_uuid=$2;");
+
+ for (unsigned int i = 0; i<RETRIES; i++)
{
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- work[i].statement,
- params,
- work[i].cb,
- &chc);
+ enum GNUNET_DB_QueryStatus qs;
+ uint64_t end;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("coin_history_serial_id",
+ &end),
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+ h_denom_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("remaining",
+ balance),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ TEH_PG_start_read_committed (pg,
+ "get-coin-transactions"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ /* First only check the last item, to see if
+ we even need to iterate */
+ qs = GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "get_coin_history_etag_balance",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_PG_rollback (pg);
+ continue;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ *etag_out = end;
+ if (end == etag_in)
+ return qs;
+ }
+ /* We indeed need to iterate over the history */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Coin %s yielded %d transactions of type %s\n",
+ "Current ETag for coin %s is %llu\n",
TALER_B2S (coin_pub),
- qs,
- work[i].statement);
- if ( (0 > qs) ||
- (chc.failed) )
+ (unsigned long long) end);
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "get_coin_history",
+ lparams,
+ &handle_history_entry,
+ &chc);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_PG_rollback (pg);
+ continue;
+ default:
+ break;
+ }
+ if (chc.failed)
+ {
+ TEH_PG_rollback (pg);
+ TEH_COMMON_free_coin_transaction_list (pg,
+ chc.head);
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+ }
+ qs = TEH_PG_commit (pg);
+ switch (qs)
{
- if (NULL != chc.head)
- TEH_COMMON_free_coin_transaction_list (cls,
- chc.head);
- *tlp = NULL;
- if (chc.failed)
- qs = GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_COMMON_free_coin_transaction_list (pg,
+ chc.head);
+ chc.head = NULL;
return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_COMMON_free_coin_transaction_list (pg,
+ chc.head);
+ chc.head = NULL;
+ continue;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ *tlp = chc.head;
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
}
- *tlp = chc.head;
- if (NULL == chc.head)
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ return GNUNET_DB_STATUS_SOFT_ERROR;
}
diff --git a/src/exchangedb/pg_get_coin_transactions.h b/src/exchangedb/pg_get_coin_transactions.h
index c95fd0947..46e32e094 100644
--- a/src/exchangedb/pg_get_coin_transactions.h
+++ b/src/exchangedb/pg_get_coin_transactions.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023 Taler Systems SA
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
@@ -27,18 +27,35 @@
/**
- * Compile a list of all (historic) transactions performed with the given coin
- * (/refresh/melt, /deposit, /refund and /recoup operations).
+ * Compile a list of (historic) transactions performed with the given coin
+ * (melt, refund, recoup and deposit operations). Should return 0 if the @a
+ * coin_pub is unknown, otherwise determine @a etag_out and if it is past @a
+ * etag_in return the history after @a start_off. @a etag_out should be set
+ * to the last row ID of the given @a coin_pub in the coin history table.
*
- * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param cls the @e cls of this struct with the plugin-specific state
* @param coin_pub coin to investigate
- * @param[out] tlp set to list of transactions, NULL if coin is fresh
+ * @param start_off starting offset from which on to return entries
+ * @param etag_in up to this offset the client already has a response, do not
+ * return anything unless @a etag_out will be larger
+ * @param[out] etag_out set to the latest history offset known for this @a coin_pub
+ * @param[out] balance set to current balance of the coin
+ * @param[out] h_denom_pub set to denomination public key of the coin
+ * @param[out] tlp set to list of transactions, set to NULL if coin has no
+ * transaction history past @a start_off or if @a etag_in is equal
+ * to the value written to @a etag_out.
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_coin_transactions (
void *cls,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t start_off,
+ uint64_t etag_in,
+ uint64_t *etag_out,
+ struct TALER_Amount *balance,
+ struct TALER_DenominationHashP *h_denom_pub,
struct TALER_EXCHANGEDB_TransactionList **tlp);
+
#endif
diff --git a/src/exchangedb/pg_get_denomination_info.c b/src/exchangedb/pg_get_denomination_info.c
index 97250b621..4bae29795 100644
--- a/src/exchangedb/pg_get_denomination_info.c
+++ b/src/exchangedb/pg_get_denomination_info.c
@@ -64,8 +64,6 @@ TEH_PG_get_denomination_info (
GNUNET_PQ_result_spec_end
};
-
- /* Used in #postgres_get_denomination_info() */
PREPARE (pg,
"denomination_get",
"SELECT"
@@ -74,19 +72,14 @@ TEH_PG_get_denomination_info (
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin" /* value of this denom */
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",age_mask"
" FROM denominations"
- " WHERE denom_pub_hash=$1;");
+ " WHERE denom_pub_hash=$1;");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"denomination_get",
params,
@@ -96,4 +89,3 @@ TEH_PG_get_denomination_info (
issue->denom_hash = *denom_pub_hash;
return qs;
}
-
diff --git a/src/exchangedb/pg_get_denomination_revocation.c b/src/exchangedb/pg_get_denomination_revocation.c
index 4d29d88c4..5e7a3a322 100644
--- a/src/exchangedb/pg_get_denomination_revocation.c
+++ b/src/exchangedb/pg_get_denomination_revocation.c
@@ -46,15 +46,15 @@ TEH_PG_get_denomination_revocation (
};
PREPARE (pg,
- "denomination_revocation_get",
- "SELECT"
- " master_sig"
- ",denom_revocations_serial_id"
- " FROM denomination_revocations"
- " WHERE denominations_serial="
- " (SELECT denominations_serial"
- " FROM denominations"
- " WHERE denom_pub_hash=$1);");
+ "denomination_revocation_get",
+ "SELECT"
+ " master_sig"
+ ",denom_revocations_serial_id"
+ " FROM denomination_revocations"
+ " WHERE denominations_serial="
+ " (SELECT denominations_serial"
+ " FROM denominations"
+ " WHERE denom_pub_hash=$1);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"denomination_revocation_get",
diff --git a/src/exchangedb/pg_get_denomination_revocation.h b/src/exchangedb/pg_get_denomination_revocation.h
index d022c822d..5f7f27227 100644
--- a/src/exchangedb/pg_get_denomination_revocation.h
+++ b/src/exchangedb/pg_get_denomination_revocation.h
@@ -41,4 +41,5 @@ TEH_PG_get_denomination_revocation (
const struct TALER_DenominationHashP *denom_pub_hash,
struct TALER_MasterSignatureP *master_sig,
uint64_t *rowid);
+
#endif
diff --git a/src/exchangedb/pg_get_drain_profit.c b/src/exchangedb/pg_get_drain_profit.c
index d02802e1d..75fccefcd 100644
--- a/src/exchangedb/pg_get_drain_profit.c
+++ b/src/exchangedb/pg_get_drain_profit.c
@@ -58,7 +58,6 @@ TEH_PG_get_drain_profit (
GNUNET_PQ_result_spec_end
};
-
PREPARE (pg,
"get_profit_drain",
"SELECT"
@@ -66,8 +65,7 @@ TEH_PG_get_drain_profit (
",account_section"
",payto_uri"
",trigger_date"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",master_sig"
" FROM profit_drains"
" WHERE wtid=$1;");
diff --git a/src/exchangedb/pg_get_expired_reserves.c b/src/exchangedb/pg_get_expired_reserves.c
index c7162dc6b..be9ece98a 100644
--- a/src/exchangedb/pg_get_expired_reserves.c
+++ b/src/exchangedb/pg_get_expired_reserves.c
@@ -84,7 +84,8 @@ reserve_expired_cb (void *cls,
&account_details),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ TALER_PQ_result_spec_amount ("current_balance",
+ pg->currency,
&remaining_balance),
GNUNET_PQ_result_spec_end
};
@@ -137,7 +138,7 @@ TEH_PG_get_expired_reserves (void *cls,
" SELECT * "
" FROM reserves "
" WHERE expiration_date <= $1 "
- " AND (current_balance_val != 0 OR current_balance_frac != 0) "
+ " AND ((current_balance).val != 0 OR (current_balance).frac != 0) "
" ORDER BY expiration_date ASC "
" LIMIT 1 "
") "
@@ -145,8 +146,7 @@ TEH_PG_get_expired_reserves (void *cls,
" ed.expiration_date "
" ,payto_uri AS account_details "
" ,ed.reserve_pub "
- " ,current_balance_val "
- " ,current_balance_frac "
+ " ,current_balance "
"FROM ( "
" SELECT "
" * "
diff --git a/src/exchangedb/pg_get_extension_manifest.c b/src/exchangedb/pg_get_extension_manifest.c
index 5e95897d3..c6b5948cf 100644
--- a/src/exchangedb/pg_get_extension_manifest.c
+++ b/src/exchangedb/pg_get_extension_manifest.c
@@ -54,13 +54,12 @@ TEH_PG_get_extension_manifest (void *cls,
};
*manifest = NULL;
- /* Used in #postgres_get_extension_manifest */
PREPARE (pg,
"get_extension_manifest",
- "SELECT "
- " manifest "
- "FROM extensions"
- " WHERE name=$1;");
+ "SELECT"
+ " manifest"
+ " FROM extensions"
+ " WHERE name=$1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_extension_manifest",
params,
diff --git a/src/exchangedb/pg_get_extension_manifest.h b/src/exchangedb/pg_get_extension_manifest.h
index 3756b7f4c..e8331ad9b 100644
--- a/src/exchangedb/pg_get_extension_manifest.h
+++ b/src/exchangedb/pg_get_extension_manifest.h
@@ -36,6 +36,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_extension_manifest (void *cls,
- const char *extension_name,
+ const char *extension_name,
char **manifest);
+
#endif
diff --git a/src/exchangedb/pg_get_global_fee.c b/src/exchangedb/pg_get_global_fee.c
index 6f6bbafef..46addfa17 100644
--- a/src/exchangedb/pg_get_global_fee.c
+++ b/src/exchangedb/pg_get_global_fee.c
@@ -28,14 +28,14 @@
enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fee (void *cls,
- struct GNUNET_TIME_Timestamp date,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_GlobalFeeSet *fees,
- struct GNUNET_TIME_Relative *purse_timeout,
- struct GNUNET_TIME_Relative *history_expiration,
- uint32_t *purse_account_limit,
- struct TALER_MasterSignatureP *master_sig)
+ struct GNUNET_TIME_Timestamp date,
+ struct GNUNET_TIME_Timestamp *start_date,
+ struct GNUNET_TIME_Timestamp *end_date,
+ struct TALER_GlobalFeeSet *fees,
+ struct GNUNET_TIME_Relative *purse_timeout,
+ struct GNUNET_TIME_Relative *history_expiration,
+ uint32_t *purse_account_limit,
+ struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -64,26 +64,21 @@ TEH_PG_get_global_fee (void *cls,
GNUNET_PQ_result_spec_end
};
-
- /* Used in #postgres_get_global_fee() */
- PREPARE(pg,
- "get_global_fee",
- "SELECT "
- " start_date"
- ",end_date"
- ",history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
- ",purse_timeout"
- ",history_expiration"
- ",purse_account_limit"
- ",master_sig"
- " FROM global_fee"
- " WHERE start_date <= $1"
- " AND end_date > $1;");
+ PREPARE (pg,
+ "get_global_fee",
+ "SELECT "
+ " start_date"
+ ",end_date"
+ ",history_fee"
+ ",account_fee"
+ ",purse_fee"
+ ",purse_timeout"
+ ",history_expiration"
+ ",purse_account_limit"
+ ",master_sig"
+ " FROM global_fee"
+ " WHERE start_date <= $1"
+ " AND end_date > $1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_global_fee",
params,
diff --git a/src/exchangedb/pg_get_global_fee.h b/src/exchangedb/pg_get_global_fee.h
index 0887d54d2..1e7c9e94b 100644
--- a/src/exchangedb/pg_get_global_fee.h
+++ b/src/exchangedb/pg_get_global_fee.h
@@ -40,13 +40,13 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fee (void *cls,
- struct GNUNET_TIME_Timestamp date,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_GlobalFeeSet *fees,
- struct GNUNET_TIME_Relative *purse_timeout,
- struct GNUNET_TIME_Relative *history_expiration,
- uint32_t *purse_account_limit,
+ struct GNUNET_TIME_Timestamp date,
+ struct GNUNET_TIME_Timestamp *start_date,
+ struct GNUNET_TIME_Timestamp *end_date,
+ struct TALER_GlobalFeeSet *fees,
+ struct GNUNET_TIME_Relative *purse_timeout,
+ struct GNUNET_TIME_Relative *history_expiration,
+ uint32_t *purse_account_limit,
struct TALER_MasterSignatureP *master_sig);
#endif
diff --git a/src/exchangedb/pg_get_global_fees.c b/src/exchangedb/pg_get_global_fees.c
index 0e1736bd4..21be35989 100644
--- a/src/exchangedb/pg_get_global_fees.c
+++ b/src/exchangedb/pg_get_global_fees.c
@@ -121,11 +121,10 @@ global_fees_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fees (void *cls,
- TALER_EXCHANGEDB_GlobalFeeCallback cb,
- void *cb_cls)
+ TALER_EXCHANGEDB_GlobalFeeCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Timestamp date
@@ -144,32 +143,23 @@ TEH_PG_get_global_fees (void *cls,
.status = GNUNET_OK
};
- /* Used in #postgres_get_global_fees() */
PREPARE (pg,
"get_global_fees",
"SELECT "
" start_date"
",end_date"
- ",history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",history_fee"
+ ",account_fee"
+ ",purse_fee"
",purse_timeout"
",history_expiration"
",purse_account_limit"
",master_sig"
" FROM global_fee"
" WHERE start_date >= $1");
-
return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"get_global_fees",
params,
&global_fees_cb,
&gctx);
}
-
-
-
-
diff --git a/src/exchangedb/pg_get_global_fees.h b/src/exchangedb/pg_get_global_fees.h
index c8f6f02c2..80c9b812f 100644
--- a/src/exchangedb/pg_get_global_fees.h
+++ b/src/exchangedb/pg_get_global_fees.h
@@ -35,6 +35,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_global_fees (void *cls,
- TALER_EXCHANGEDB_GlobalFeeCallback cb,
+ TALER_EXCHANGEDB_GlobalFeeCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_get_known_coin.c b/src/exchangedb/pg_get_known_coin.c
index fe5c683bc..2c4a82d67 100644
--- a/src/exchangedb/pg_get_known_coin.c
+++ b/src/exchangedb/pg_get_known_coin.c
@@ -27,8 +27,8 @@
enum GNUNET_DB_QueryStatus
TEH_PG_get_known_coin (void *cls,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- struct TALER_CoinPublicInfo *coin_info)
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_CoinPublicInfo *coin_info)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -51,9 +51,6 @@ TEH_PG_get_known_coin (void *cls,
"Getting known coin data for coin %s\n",
TALER_B2S (coin_pub));
coin_info->coin_pub = *coin_pub;
- /* Used in #postgres_get_known_coin() to fetch
- the denomination public key and signature for
- a coin known to the exchange. */
PREPARE (pg,
"get_known_coin",
"SELECT"
@@ -63,7 +60,6 @@ TEH_PG_get_known_coin (void *cls,
" FROM known_coins"
" JOIN denominations USING (denominations_serial)"
" WHERE coin_pub=$1;");
-
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_known_coin",
params,
diff --git a/src/exchangedb/pg_get_known_coin.h b/src/exchangedb/pg_get_known_coin.h
index d7f55b33c..c34bd2a97 100644
--- a/src/exchangedb/pg_get_known_coin.h
+++ b/src/exchangedb/pg_get_known_coin.h
@@ -34,7 +34,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_known_coin (void *cls,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
struct TALER_CoinPublicInfo *coin_info);
#endif
diff --git a/src/exchangedb/pg_get_link_data.c b/src/exchangedb/pg_get_link_data.c
index f167b3b6e..1b0cb3e20 100644
--- a/src/exchangedb/pg_get_link_data.c
+++ b/src/exchangedb/pg_get_link_data.c
@@ -48,43 +48,41 @@ struct LinkDataContext
struct TALER_TransferPublicKeyP transfer_pub;
/**
- * Link data for @e transfer_pub
- */
- struct TALER_EXCHANGEDB_LinkList *last;
-
- /**
* Status, set to #GNUNET_SYSERR on errors,
*/
enum GNUNET_GenericReturnValue status;
};
-struct Results {
- struct TALER_EXCHANGEDB_LinkList *pos;
- struct TALER_TransferPublicKeyP transfer_pub;
- };
+
/**
* 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
-free_link_data_list (void *cls,
- struct TALER_EXCHANGEDB_LinkList *ldl)
+free_link_data_list (struct TALER_EXCHANGEDB_LinkList *ldl)
{
struct TALER_EXCHANGEDB_LinkList *next;
- (void) cls;
while (NULL != ldl)
{
next = ldl->next;
TALER_denom_pub_free (&ldl->denom_pub);
TALER_blinded_denom_sig_free (&ldl->ev_sig);
+ TALER_denom_ewv_free (&ldl->alg_values);
GNUNET_free (ldl);
ldl = next;
}
}
+
+struct Results
+{
+ struct TALER_EXCHANGEDB_LinkList *pos;
+ struct TALER_TransferPublicKeyP transfer_pub;
+};
+
+
static int
transfer_pub_cmp (const void *a,
const void *b)
@@ -96,6 +94,7 @@ transfer_pub_cmp (const void *a,
&rb->transfer_pub);
}
+
/**
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
@@ -110,22 +109,20 @@ add_ldl (void *cls,
unsigned int num_results)
{
struct LinkDataContext *ldctx = cls;
- struct Results *temp= GNUNET_new_array (num_results,
- struct Results);;
+ struct Results *temp = GNUNET_new_array (num_results,
+ struct Results);
unsigned int temp_off = 0;
-
for (int i = num_results - 1; i >= 0; i--)
{
struct TALER_EXCHANGEDB_LinkList *pos;
- struct TALER_TransferPublicKeyP transfer_pub;
pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList);
{
struct TALER_BlindedPlanchet bp;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
- &transfer_pub),
+ &temp[temp_off].transfer_pub),
GNUNET_PQ_result_spec_auto_from_type ("link_sig",
&pos->orig_coin_link_sig),
TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
@@ -151,73 +148,52 @@ add_ldl (void *cls,
ldctx->status = GNUNET_SYSERR;
return;
}
- if (TALER_DENOMINATION_CS == bp.cipher)
+ if (GNUNET_CRYPTO_BSA_CS == bp.blinded_message->cipher)
{
- pos->nonce = bp.details.cs_blinded_planchet.nonce;
+ pos->nonce.cs_nonce
+ = bp.blinded_message->details.cs_blinded_message.nonce;
pos->have_nonce = true;
}
TALER_blinded_planchet_free (&bp);
}
- temp[temp_off].pos = pos;
- temp[temp_off].transfer_pub = transfer_pub;
- temp_off++;
+ temp[temp_off].pos = pos;
+ temp_off++;
}
qsort (temp,
temp_off,
sizeof (struct Results),
- transfer_pub_cmp);
- for (unsigned int i = 0; i < temp_off; i++)
- {
- struct TALER_EXCHANGEDB_LinkList *pos;
- struct Results *r = &temp[i];
-
- pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList);
- pos->orig_coin_link_sig = r->pos->orig_coin_link_sig;
- pos->ev_sig = r->pos->ev_sig;
- pos->coin_refresh_offset = r->pos->coin_refresh_offset;
- pos->alg_values = r->pos->alg_values;
- pos->denom_pub = r->pos->denom_pub;
- pos->nonce = r->pos->nonce;
- pos->have_nonce = r->pos->have_nonce;
-
- pos->next = ldctx->last;
- ldctx->last = pos;
- }
-
- if (NULL != ldctx->last)
+ &transfer_pub_cmp);
+ if (temp_off > 0)
{
- ldctx->ldc (ldctx->ldc_cls,
- &ldctx->transfer_pub,
- ldctx->last);
- free_link_data_list (ldctx,
- ldctx->last);
- }
-
- ldctx->last = NULL;
+ struct TALER_EXCHANGEDB_LinkList *head = NULL;
- GNUNET_free(temp);
- /*
- if ( (NULL != ldctx->last) &&
- (0 == GNUNET_memcmp (&transfer_pub,
- &ldctx->transfer_pub)) )
- {
- pos->next = ldctx->last;
- }
- else
+ head = temp[0].pos;
+ for (unsigned int i = 1; i < temp_off; i++)
{
- if (NULL != ldctx->last)
+ struct TALER_EXCHANGEDB_LinkList *pos = temp[i].pos;
+ const struct TALER_TransferPublicKeyP *tp = &temp[i].transfer_pub;
+
+ if (0 == GNUNET_memcmp (tp,
+ &temp[i - 1].transfer_pub))
+ {
+ pos->next = head;
+ head = pos;
+ }
+ else
{
ldctx->ldc (ldctx->ldc_cls,
- &ldctx->transfer_pub,
- ldctx->last);
- free_link_data_list (cls,
- ldctx->last);
+ &temp[i - 1].transfer_pub,
+ head);
+ free_link_data_list (head);
+ head = pos;
}
- ldctx->transfer_pub = transfer_pub;
}
- ldctx->last = pos;
+ ldctx->ldc (ldctx->ldc_cls,
+ &temp[temp_off - 1].transfer_pub,
+ head);
+ free_link_data_list (head);
}
- GNUNET_free(temp);*/
+ GNUNET_free (temp);
}
@@ -239,7 +215,7 @@ TEH_PG_get_link_data (void *cls,
if (-2 == percent_refund)
{
- const char *mode = getenv ("NEW_LOGIC");
+ const char *mode = getenv ("TALER_POSTGRES_GET_LINK_DATA_LOGIC");
char dummy;
if ( (NULL==mode) ||
@@ -252,7 +228,7 @@ TEH_PG_get_link_data (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad mode `%s' specified\n",
mode);
- percent_refund = 0;
+ percent_refund = 4; /* Fastest known */
}
}
switch (percent_refund)
@@ -325,7 +301,7 @@ TEH_PG_get_link_data (void *cls,
" ,coin_ev BYTEA);");
break;
case 3:
- query="get_link_v3";
+ query = "get_link_v3";
PREPARE (pg,
query,
"SELECT "
@@ -346,7 +322,7 @@ TEH_PG_get_link_data (void *cls,
" WHERE old_coin_pub=$1");
break;
case 4:
- query="get_link_v4";
+ query = "get_link_v4";
PREPARE (pg,
query,
"WITH rc AS MATERIALIZED ("
@@ -370,7 +346,7 @@ TEH_PG_get_link_data (void *cls,
" JOIN denominations denoms"
" USING (denominations_serial)"
" WHERE rrc.melt_serial_id = (SELECT melt_serial_id FROM rc)"
- );
+ );
break;
default:
GNUNET_break (0);
@@ -379,26 +355,12 @@ TEH_PG_get_link_data (void *cls,
ldctx.ldc = ldc;
ldctx.ldc_cls = ldc_cls;
- ldctx.last = NULL;
ldctx.status = GNUNET_OK;
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
query,
params,
&add_ldl,
&ldctx);
- if (NULL != ldctx.last)
- {
- if (GNUNET_OK == ldctx.status)
- {
- /* call callback one more time! */
- ldc (ldc_cls,
- &ldctx.transfer_pub,
- ldctx.last);
- }
- free_link_data_list (cls,
- ldctx.last);
- ldctx.last = NULL;
- }
if (GNUNET_OK != ldctx.status)
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
diff --git a/src/exchangedb/pg_get_melt.c b/src/exchangedb/pg_get_melt.c
index f239c605b..2221054ba 100644
--- a/src/exchangedb/pg_get_melt.c
+++ b/src/exchangedb/pg_get_melt.c
@@ -28,9 +28,9 @@
enum GNUNET_DB_QueryStatus
TEH_PG_get_melt (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- struct TALER_EXCHANGEDB_Melt *melt,
- uint64_t *melt_serial_id)
+ const struct TALER_RefreshCommitmentP *rc,
+ struct TALER_EXCHANGEDB_Melt *melt,
+ uint64_t *melt_serial_id)
{
struct PostgresClosure *pg = cls;
bool h_age_commitment_is_null;
@@ -66,19 +66,17 @@ TEH_PG_get_melt (void *cls,
0,
sizeof (melt->session.coin.denom_sig));
- /* Used in #postgres_get_melt() to fetch
- high-level information about a melt operation */
+ /* Used in #postgres_get_melt() to fetch
+ high-level information about a melt operation */
PREPARE (pg,
"get_melt",
/* "SELECT"
" denoms.denom_pub_hash"
- ",denoms.fee_refresh_val"
- ",denoms.fee_refresh_frac"
+ ",denoms.fee_refresh"
",old_coin_pub"
",old_coin_sig"
",kc.age_commitment_hash"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",melt_serial_id"
" FROM refresh_commitments"
@@ -94,13 +92,11 @@ TEH_PG_get_melt (void *cls,
")"
"SELECT"
" denoms.denom_pub_hash"
- ",denoms.fee_refresh_val"
- ",denoms.fee_refresh_frac"
+ ",denoms.fee_refresh"
",rc.old_coin_pub"
",rc.old_coin_sig"
",kc.age_commitment_hash"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",melt_serial_id "
"FROM ("
diff --git a/src/exchangedb/pg_get_melt.h b/src/exchangedb/pg_get_melt.h
index 73d757a05..269960bad 100644
--- a/src/exchangedb/pg_get_melt.h
+++ b/src/exchangedb/pg_get_melt.h
@@ -37,8 +37,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_melt (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- struct TALER_EXCHANGEDB_Melt *melt,
+ const struct TALER_RefreshCommitmentP *rc,
+ struct TALER_EXCHANGEDB_Melt *melt,
uint64_t *melt_serial_id);
#endif
diff --git a/src/exchangedb/pg_get_old_coin_by_h_blind.c b/src/exchangedb/pg_get_old_coin_by_h_blind.c
index 385c3f1d1..dcce7b32f 100644
--- a/src/exchangedb/pg_get_old_coin_by_h_blind.c
+++ b/src/exchangedb/pg_get_old_coin_by_h_blind.c
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
enum GNUNET_DB_QueryStatus
TEH_PG_get_old_coin_by_h_blind (
void *cls,
@@ -47,7 +46,7 @@ TEH_PG_get_old_coin_by_h_blind (
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_get_old_coin_by_h_blind() */
+ /* Used in #postgres_get_old_coin_by_h_blind() */
PREPARE (pg,
"old_coin_by_h_blind",
"SELECT"
diff --git a/src/exchangedb/pg_get_old_coin_by_h_blind.h b/src/exchangedb/pg_get_old_coin_by_h_blind.h
index 1404990d9..93ed541b6 100644
--- a/src/exchangedb/pg_get_old_coin_by_h_blind.h
+++ b/src/exchangedb/pg_get_old_coin_by_h_blind.h
@@ -41,4 +41,5 @@ TEH_PG_get_old_coin_by_h_blind (
const struct TALER_BlindedCoinHashP *h_blind_ev,
struct TALER_CoinSpendPublicKeyP *old_coin_pub,
uint64_t *rrc_serial);
+
#endif
diff --git a/src/exchangedb/pg_get_pending_kyc_requirement_process.c b/src/exchangedb/pg_get_pending_kyc_requirement_process.c
new file mode 100644
index 000000000..b9acddad1
--- /dev/null
+++ b/src/exchangedb/pg_get_pending_kyc_requirement_process.c
@@ -0,0 +1,66 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_pending_kyc_requirement_process.c
+ * @brief Implementation of the get_pending_kyc_requirement_process function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_get_pending_kyc_requirement_process.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_pending_kyc_requirement_process (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ const char *provider_section,
+ char **redirect_url)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (provider_section),
+ GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("redirect_url",
+ redirect_url),
+ NULL),
+ GNUNET_PQ_result_spec_end
+ };
+
+ *redirect_url = NULL;
+ PREPARE (pg,
+ "get_pending_kyc_requirement_process",
+ "SELECT"
+ " redirect_url"
+ " FROM legitimization_processes"
+ " WHERE provider_section=$1"
+ " AND h_payto=$2"
+ " AND NOT finished"
+ " ORDER BY start_time DESC"
+ " LIMIT 1");
+ return GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "get_pending_kyc_requirement_process",
+ params,
+ rs);
+}
diff --git a/src/exchangedb/pg_insert_deposit.h b/src/exchangedb/pg_get_pending_kyc_requirement_process.h
index 15de39eff..738c4d65b 100644
--- a/src/exchangedb/pg_insert_deposit.h
+++ b/src/exchangedb/pg_get_pending_kyc_requirement_process.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2023 Taler Systems SA
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
@@ -14,27 +14,32 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_insert_deposit.h
- * @brief implementation of the insert_deposit function for Postgres
+ * @file exchangedb/pg_get_pending_kyc_requirement_process.h
+ * @brief implementation of the get_pending_kyc_requirement_process function for Postgres
* @author Christian Grothoff
*/
-#ifndef PG_INSERT_DEPOSIT_H
-#define PG_INSERT_DEPOSIT_H
+#ifndef PG_GET_PENDING_KYC_REQUIREMENT_PROCESS_H
+#define PG_GET_PENDING_KYC_REQUIREMENT_PROCESS_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
+
+
/**
- * Insert information about deposited coin into the database.
+ * Fetch information about pending KYC requirement process.
*
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param exchange_timestamp time the exchange received the deposit request
- * @param deposit deposit information to store
- * @return query result status
+ * @param cls closure
+ * @param h_payto account that must be KYC'ed
+ * @param provider_section provider that must be checked
+ * @param[out] redirect_url set to redirect URL for the process
+ * @return database transaction status
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_insert_deposit (void *cls,
- struct GNUNET_TIME_Timestamp exchange_timestamp,
- const struct TALER_EXCHANGEDB_Deposit *deposit);
+TEH_PG_get_pending_kyc_requirement_process (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ const char *provider_section,
+ char **redirect_url);
#endif
diff --git a/src/exchangedb/pg_get_policy_details.c b/src/exchangedb/pg_get_policy_details.c
index fafdca53c..6e1b5c5dc 100644
--- a/src/exchangedb/pg_get_policy_details.c
+++ b/src/exchangedb/pg_get_policy_details.c
@@ -57,7 +57,6 @@ TEH_PG_get_policy_details (
};
-
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_policy_details",
params,
diff --git a/src/exchangedb/pg_get_purse_deposit.c b/src/exchangedb/pg_get_purse_deposit.c
index 539bd5ece..cb24855a1 100644
--- a/src/exchangedb/pg_get_purse_deposit.c
+++ b/src/exchangedb/pg_get_purse_deposit.c
@@ -59,25 +59,24 @@ TEH_PG_get_purse_deposit (
GNUNET_PQ_result_spec_end
};
-
*partner_url = NULL;
- /* Used in #postgres_get_purse_deposit */
PREPARE (pg,
"select_purse_deposit_by_coin_pub",
"SELECT "
" coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",denom_pub_hash"
",age_commitment_hash"
",partner_base_url"
" FROM purse_deposits"
- " LEFT JOIN partners USING (partner_serial_id)"
- " JOIN known_coins kc USING (coin_pub)"
- " JOIN denominations USING (denominations_serial)"
- " WHERE coin_pub=$2"
- " AND purse_pub=$1;");
-
+ " LEFT JOIN partners"
+ " USING (partner_serial_id)"
+ " JOIN known_coins kc"
+ " USING (coin_pub)"
+ " JOIN denominations"
+ " USING (denominations_serial)"
+ " WHERE purse_pub=$1"
+ " AND coin_pub=$2;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_purse_deposit_by_coin_pub",
params,
diff --git a/src/exchangedb/pg_get_purse_request.c b/src/exchangedb/pg_get_purse_request.c
index ba8182857..9d2ee5654 100644
--- a/src/exchangedb/pg_get_purse_request.c
+++ b/src/exchangedb/pg_get_purse_request.c
@@ -59,7 +59,7 @@ TEH_PG_get_purse_request (
purse_sig),
GNUNET_PQ_result_spec_end
};
-
+
PREPARE (pg,
"get_purse_request",
"SELECT "
@@ -67,17 +67,13 @@ TEH_PG_get_purse_request (
",purse_expiration"
",h_contract_terms"
",age_limit"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",balance_val"
- ",balance_frac"
+ ",amount_with_fee"
+ ",balance"
",purse_sig"
" FROM purse_requests"
" WHERE purse_pub=$1;");
-
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_purse_request",
params,
rs);
}
-
diff --git a/src/exchangedb/pg_get_ready_deposit.c b/src/exchangedb/pg_get_ready_deposit.c
index 91151c617..d8344faf1 100644
--- a/src/exchangedb/pg_get_ready_deposit.c
+++ b/src/exchangedb/pg_get_ready_deposit.c
@@ -33,7 +33,6 @@ TEH_PG_get_ready_deposit (void *cls,
struct TALER_MerchantPublicKeyP *merchant_pub,
char **payto_uri)
{
- static int choose_mode = -2;
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Absolute now
= GNUNET_TIME_absolute_get ();
@@ -50,76 +49,24 @@ TEH_PG_get_ready_deposit (void *cls,
payto_uri),
GNUNET_PQ_result_spec_end
};
- const char *query;
-
- if (-2 == choose_mode)
- {
- const char *mode = getenv ("TALER_POSTGRES_GET_READY_LOGIC");
- char dummy;
-
- if ( (NULL==mode) ||
- (1 != sscanf (mode,
- "%d%c",
- &choose_mode,
- &dummy)) )
- {
- if (NULL != mode)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Bad mode `%s' specified\n",
- mode);
- choose_mode = 0;
- }
- }
- switch (choose_mode)
- {
- case 0:
- query = "deposits_get_ready-v5";
- PREPARE (pg,
- query,
- "SELECT"
- " payto_uri"
- ",merchant_pub"
- " FROM deposits dep"
- " JOIN wire_targets wt"
- " USING (wire_target_h_payto)"
- " WHERE NOT (done OR policy_blocked)"
- " AND dep.wire_deadline<=$1"
- " AND dep.shard >= $2"
- " AND dep.shard <= $3"
- " ORDER BY "
- " dep.wire_deadline ASC"
- " ,dep.shard ASC"
- " LIMIT 1;");
- break;
- case 1:
- query = "deposits_get_ready-v6";
- PREPARE (pg,
- query,
- "WITH rc AS MATERIALIZED ("
- " SELECT"
- " merchant_pub"
- ",wire_target_h_payto"
- " FROM deposits"
- " WHERE NOT (done OR policy_blocked)"
- " AND wire_deadline<=$1"
- " AND shard >= $2"
- " AND shard <= $3"
- " ORDER BY wire_deadline ASC"
- " ,shard ASC"
- " LIMIT 1"
- ")"
- "SELECT"
- " wt.payto_uri"
- ",rc.merchant_pub"
- " FROM wire_targets wt"
- " JOIN rc"
- " USING (wire_target_h_payto);");
- break;
- default:
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
+ const char *query = "deposits_get_ready";
+ PREPARE (pg,
+ query,
+ "SELECT"
+ " wts.payto_uri"
+ ",bdep.merchant_pub"
+ " FROM batch_deposits bdep"
+ " JOIN wire_targets wts"
+ " USING (wire_target_h_payto)"
+ " WHERE NOT (bdep.done OR bdep.policy_blocked)"
+ " AND bdep.wire_deadline<=$1"
+ " AND bdep.shard >= $2"
+ " AND bdep.shard <= $3"
+ " ORDER BY "
+ " bdep.wire_deadline ASC"
+ " ,bdep.shard ASC"
+ " LIMIT 1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
query,
params,
diff --git a/src/exchangedb/pg_get_ready_deposit.h b/src/exchangedb/pg_get_ready_deposit.h
index 19b6dafe4..b1dd7a968 100644
--- a/src/exchangedb/pg_get_ready_deposit.h
+++ b/src/exchangedb/pg_get_ready_deposit.h
@@ -38,9 +38,9 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_ready_deposit (void *cls,
- uint64_t start_shard_row,
- uint64_t end_shard_row,
- struct TALER_MerchantPublicKeyP *merchant_pub,
+ uint64_t start_shard_row,
+ uint64_t end_shard_row,
+ struct TALER_MerchantPublicKeyP *merchant_pub,
char **payto_uri);
#endif
diff --git a/src/exchangedb/pg_get_refresh_reveal.c b/src/exchangedb/pg_get_refresh_reveal.c
index e2db082b7..08d4b21a5 100644
--- a/src/exchangedb/pg_get_refresh_reveal.c
+++ b/src/exchangedb/pg_get_refresh_reveal.c
@@ -112,7 +112,8 @@ add_revealed_coins (void *cls,
GNUNET_PQ_result_spec_end
};
- if (TALER_DENOMINATION_INVALID != rrc->blinded_planchet.cipher)
+ if (NULL !=
+ rrc->blinded_planchet.blinded_message)
{
/* duplicate offset, not allowed */
GNUNET_break (0);
@@ -133,14 +134,11 @@ add_revealed_coins (void *cls,
}
-
-
-
enum GNUNET_DB_QueryStatus
TEH_PG_get_refresh_reveal (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- TALER_EXCHANGEDB_RefreshCallback cb,
- void *cb_cls)
+ const struct TALER_RefreshCommitmentP *rc,
+ TALER_EXCHANGEDB_RefreshCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GetRevealContext grctx;
@@ -154,8 +152,8 @@ TEH_PG_get_refresh_reveal (void *cls,
0,
sizeof (grctx));
- /* Obtain information about the coins created in a refresh
- operation, used in #postgres_get_refresh_reveal() */
+ /* Obtain information about the coins created in a refresh
+ operation, used in #postgres_get_refresh_reveal() */
PREPARE (pg,
"get_refresh_revealed_coins",
"SELECT "
@@ -208,6 +206,7 @@ cleanup:
TALER_blinded_denom_sig_free (&rrc->coin_sig);
TALER_blinded_planchet_free (&rrc->blinded_planchet);
+ TALER_denom_ewv_free (&rrc->exchange_vals);
}
GNUNET_free (grctx.rrcs);
return qs;
diff --git a/src/exchangedb/pg_get_refresh_reveal.h b/src/exchangedb/pg_get_refresh_reveal.h
index 0fcea26cd..15b57b343 100644
--- a/src/exchangedb/pg_get_refresh_reveal.h
+++ b/src/exchangedb/pg_get_refresh_reveal.h
@@ -37,8 +37,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_refresh_reveal (void *cls,
- const struct TALER_RefreshCommitmentP *rc,
- TALER_EXCHANGEDB_RefreshCallback cb,
+ const struct TALER_RefreshCommitmentP *rc,
+ TALER_EXCHANGEDB_RefreshCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_get_reserve_balance.c b/src/exchangedb/pg_get_reserve_balance.c
index e08261fc0..140bf3b70 100644
--- a/src/exchangedb/pg_get_reserve_balance.c
+++ b/src/exchangedb/pg_get_reserve_balance.c
@@ -27,8 +27,8 @@
enum GNUNET_DB_QueryStatus
TEH_PG_get_reserve_balance (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- struct TALER_Amount *balance)
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct TALER_Amount *balance)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -36,7 +36,8 @@ TEH_PG_get_reserve_balance (void *cls,
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ TALER_PQ_result_spec_amount ("current_balance",
+ pg->currency,
balance),
GNUNET_PQ_result_spec_end
};
@@ -44,8 +45,7 @@ TEH_PG_get_reserve_balance (void *cls,
PREPARE (pg,
"get_reserve_balance",
"SELECT"
- " current_balance_val"
- ",current_balance_frac"
+ " current_balance"
" FROM reserves"
" WHERE reserve_pub=$1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
diff --git a/src/exchangedb/pg_get_reserve_balance.h b/src/exchangedb/pg_get_reserve_balance.h
index fd15f0d80..6dc88d906 100644
--- a/src/exchangedb/pg_get_reserve_balance.h
+++ b/src/exchangedb/pg_get_reserve_balance.h
@@ -34,7 +34,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_reserve_balance (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_Amount *balance);
#endif
diff --git a/src/exchangedb/pg_get_reserve_by_h_blind.c b/src/exchangedb/pg_get_reserve_by_h_blind.c
index 2105b4766..f87fe6cd4 100644
--- a/src/exchangedb/pg_get_reserve_by_h_blind.c
+++ b/src/exchangedb/pg_get_reserve_by_h_blind.c
@@ -45,7 +45,7 @@ TEH_PG_get_reserve_by_h_blind (
reserve_out_serial_id),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_get_reserve_by_h_blind() */
+ /* Used in #postgres_get_reserve_by_h_blind() */
PREPARE (pg,
"reserve_by_h_blind",
"SELECT"
diff --git a/src/exchangedb/pg_get_reserve_history.c b/src/exchangedb/pg_get_reserve_history.c
index 6c12abc61..1f1ca95b5 100644
--- a/src/exchangedb/pg_get_reserve_history.c
+++ b/src/exchangedb/pg_get_reserve_history.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -15,7 +15,7 @@
*/
/**
* @file pg_get_reserve_history.c
- * @brief Low-level (statement-level) Postgres database access for the exchange
+ * @brief Obtain (parts of) the history of a reserve.
* @author Christian Grothoff
*/
#include "platform.h"
@@ -23,10 +23,21 @@
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_get_reserve_history.h"
+#include "pg_start_read_committed.h"
+#include "pg_commit.h"
+#include "pg_rollback.h"
#include "plugin_exchangedb_common.h"
#include "pg_helper.h"
/**
+ * How often do we re-try when encountering DB serialization issues?
+ * (We are read-only, so can only happen due to concurrent insert,
+ * which should be very rare.)
+ */
+#define RETRIES 3
+
+
+/**
* Closure for callbacks invoked via #TEH_PG_get_reserve_history().
*/
struct ReserveHistoryContext
@@ -63,10 +74,10 @@ struct ReserveHistoryContext
struct TALER_Amount balance_out;
/**
- * Set to #GNUNET_SYSERR on serious internal errors during
+ * Set to true on serious internal errors during
* the callbacks.
*/
- enum GNUNET_GenericReturnValue status;
+ bool failed;
};
@@ -138,7 +149,7 @@ add_bank_to_exchange (void *cls,
{
GNUNET_break (0);
GNUNET_free (bt);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
}
@@ -199,7 +210,7 @@ add_withdraw_coin (void *cls,
{
GNUNET_break (0);
GNUNET_free (cbc);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
}
@@ -263,7 +274,7 @@ add_recoup (void *cls,
{
GNUNET_break (0);
GNUNET_free (recoup);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
}
@@ -323,7 +334,7 @@ add_exchange_to_bank (void *cls,
{
GNUNET_break (0);
GNUNET_free (closing);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
}
@@ -397,7 +408,7 @@ add_p2p_merge (void *cls,
{
GNUNET_break (0);
GNUNET_free (merge);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
merge->flags = (enum TALER_WalletAccountMergeFlags) flags32;
@@ -433,62 +444,6 @@ add_p2p_merge (void *cls,
* @param num_results number of rows in @a result
*/
static void
-add_history_requests (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct ReserveHistoryContext *rhc = cls;
- struct PostgresClosure *pg = rhc->pg;
-
- while (0 < num_results)
- {
- struct TALER_EXCHANGEDB_HistoryRequest *history;
- struct TALER_EXCHANGEDB_ReserveHistory *tail;
-
- history = GNUNET_new (struct TALER_EXCHANGEDB_HistoryRequest);
- {
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
- &history->history_fee),
- GNUNET_PQ_result_spec_timestamp ("request_timestamp",
- &history->request_timestamp),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
- &history->reserve_sig),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- --num_results))
- {
- GNUNET_break (0);
- GNUNET_free (history);
- rhc->status = GNUNET_SYSERR;
- return;
- }
- }
- GNUNET_assert (0 <=
- TALER_amount_add (&rhc->balance_out,
- &rhc->balance_out,
- &history->history_fee));
- history->reserve_pub = *rhc->reserve_pub;
- tail = append_rh (rhc);
- tail->type = TALER_EXCHANGEDB_RO_HISTORY_REQUEST;
- tail->details.history = history;
- }
-}
-
-
-/**
- * Add paid for history requests to result set for
- * #TEH_PG_get_reserve_history.
- *
- * @param cls a `struct ReserveHistoryContext *`
- * @param result SQL result
- * @param num_results number of rows in @a result
- */
-static void
add_open_requests (void *cls,
PGresult *result,
unsigned int num_results)
@@ -524,7 +479,7 @@ add_open_requests (void *cls,
{
GNUNET_break (0);
GNUNET_free (orq);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
}
@@ -580,7 +535,7 @@ add_close_requests (void *cls,
{
GNUNET_break (0);
GNUNET_free (crq);
- rhc->status = GNUNET_SYSERR;
+ rhc->failed = true;
return;
}
TALER_payto_hash (payto_uri,
@@ -595,17 +550,25 @@ add_close_requests (void *cls,
}
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_history (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- struct TALER_Amount *balance,
- struct TALER_EXCHANGEDB_ReserveHistory **rhp)
+/**
+ * Add reserve history entries found.
+ *
+ * @param cls a `struct ReserveHistoryContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+handle_history_entry (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- struct ReserveHistoryContext rhc;
- struct
+ static const struct
{
/**
+ * Table with reserve history entry we are responsible for.
+ */
+ const char *table;
+ /**
* Name of the prepared statement to run.
*/
const char *statement;
@@ -615,475 +578,229 @@ TEH_PG_get_reserve_history (void *cls,
GNUNET_PQ_PostgresResultHandler cb;
} work[] = {
/** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
- { "reserves_in_get_transactions",
+ { "reserves_in",
+ "reserves_in_get_transactions",
add_bank_to_exchange },
/** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
- { "get_reserves_out",
+ { "reserves_out",
+ "get_reserves_out",
&add_withdraw_coin },
/** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
- { "recoup_by_reserve",
+ { "recoup",
+ "recoup_by_reserve",
&add_recoup },
/** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
- { "close_by_reserve",
+ { "reserves_close",
+ "close_by_reserve",
&add_exchange_to_bank },
/** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
- { "merge_by_reserve",
+ { "purse_decision",
+ "merge_by_reserve",
&add_p2p_merge },
- /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
- { "history_by_reserve",
- &add_history_requests },
/** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */
- { "open_request_by_reserve",
+ { "reserves_open_requests",
+ "open_request_by_reserve",
&add_open_requests },
/** #TALER_EXCHANGEDB_RO_CLOSE_REQUEST */
- { "close_request_by_reserve",
+ { "close_requests",
+ "close_request_by_reserve",
&add_close_requests },
/* List terminator */
- { NULL,
- NULL }
+ { NULL, NULL, NULL }
+ };
+ struct ReserveHistoryContext *rhc = cls;
+ char *table_name;
+ uint64_t serial_id;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("table_name",
+ &table_name),
+ GNUNET_PQ_result_spec_uint64 ("serial_id",
+ &serial_id),
+ GNUNET_PQ_result_spec_end
};
- enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (rhc->reserve_pub),
+ GNUNET_PQ_query_param_uint64 (&serial_id),
GNUNET_PQ_query_param_end
};
- PREPARE (pg,
- "reserves_in_get_transactions",
- /*
- "SELECT"
- " wire_reference"
- ",credit_val"
- ",credit_frac"
- ",execution_date"
- ",payto_uri AS sender_account_details"
- " FROM reserves_in"
- " JOIN wire_targets"
- " ON (wire_source_h_payto = wire_target_h_payto)"
- " WHERE reserve_pub=$1;",
- */
- "WITH ri AS MATERIALIZED ( "
- " SELECT * "
- " FROM reserves_in "
- " WHERE reserve_pub = $1 "
- ") "
- "SELECT "
- " wire_reference "
- " ,credit_val "
- " ,credit_frac "
- " ,execution_date "
- " ,payto_uri AS sender_account_details "
- "FROM wire_targets "
- "JOIN ri "
- " ON (wire_target_h_payto = wire_source_h_payto) "
- "WHERE wire_target_h_payto = ( "
- " SELECT wire_source_h_payto FROM ri "
- "); ");
- PREPARE (pg,
- "get_reserves_out",
- /*
- "SELECT"
- " ro.h_blind_ev"
- ",denom.denom_pub_hash"
- ",ro.denom_sig"
- ",ro.reserve_sig"
- ",ro.execution_date"
- ",ro.amount_with_fee_val"
- ",ro.amount_with_fee_frac"
- ",denom.fee_withdraw_val"
- ",denom.fee_withdraw_frac"
- " FROM reserves res"
- " JOIN reserves_out_by_reserve ror"
- " ON (res.reserve_uuid = ror.reserve_uuid)"
- " JOIN reserves_out ro"
- " ON (ro.h_blind_ev = ror.h_blind_ev)"
- " JOIN denominations denom"
- " ON (ro.denominations_serial = denom.denominations_serial)"
- " WHERE res.reserve_pub=$1;",
- */
- "WITH robr AS MATERIALIZED ( "
- " SELECT h_blind_ev "
- " FROM reserves_out_by_reserve "
- " WHERE reserve_uuid= ( "
- " SELECT reserve_uuid "
- " FROM reserves "
- " WHERE reserve_pub = $1 "
- " ) "
- ") SELECT "
- " ro.h_blind_ev "
- " ,denom.denom_pub_hash "
- " ,ro.denom_sig "
- " ,ro.reserve_sig "
- " ,ro.execution_date "
- " ,ro.amount_with_fee_val "
- " ,ro.amount_with_fee_frac "
- " ,denom.fee_withdraw_val "
- " ,denom.fee_withdraw_frac "
- "FROM robr "
- "JOIN reserves_out ro "
- " ON (ro.h_blind_ev = robr.h_blind_ev) "
- "JOIN denominations denom "
- " ON (ro.denominations_serial = denom.denominations_serial);");
- PREPARE (pg,
- "recoup_by_reserve",
- /*
- "SELECT"
- " recoup.coin_pub"
- ",recoup.coin_sig"
- ",recoup.coin_blind"
- ",recoup.amount_val"
- ",recoup.amount_frac"
- ",recoup.recoup_timestamp"
- ",denominations.denom_pub_hash"
- ",known_coins.denom_sig"
- " FROM denominations"
- " JOIN (known_coins"
- " JOIN recoup "
- " ON (recoup.coin_pub = known_coins.coin_pub))"
- " ON (known_coins.denominations_serial = denominations.denominations_serial)"
- " WHERE recoup.coin_pub"
- " IN (SELECT coin_pub"
- " FROM recoup_by_reserve"
- " JOIN (reserves_out"
- " JOIN (reserves_out_by_reserve"
- " JOIN reserves"
- " ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))"
- " ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))"
- " ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)"
- " WHERE reserves.reserve_pub=$1);",
- */
- "SELECT robr.coin_pub "
- " ,robr.coin_sig "
- " ,robr.coin_blind "
- " ,robr.amount_val "
- " ,robr.amount_frac "
- " ,robr.recoup_timestamp "
- " ,denominations.denom_pub_hash "
- " ,robr.denom_sig "
- "FROM denominations "
- " JOIN exchange_do_recoup_by_reserve($1) robr"
- " USING (denominations_serial);");
- PREPARE (pg,
- "close_by_reserve",
- "SELECT"
- " amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",execution_date"
- ",payto_uri AS receiver_account"
- ",wtid"
- " FROM reserves_close"
- " JOIN wire_targets"
- " USING (wire_target_h_payto)"
- " WHERE reserve_pub=$1;");
- PREPARE (pg,
- "merge_by_reserve",
- "SELECT"
- " pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
- ",pr.balance_val"
- ",pr.balance_frac"
- ",pr.purse_fee_val"
- ",pr.purse_fee_frac"
- ",pr.h_contract_terms"
- ",pr.merge_pub"
- ",am.reserve_sig"
- ",pm.purse_pub"
- ",pm.merge_timestamp"
- ",pr.purse_expiration"
- ",pr.age_limit"
- ",pr.flags"
- " FROM purse_merges pm"
- " JOIN purse_requests pr"
- " USING (purse_pub)"
- " LEFT JOIN purse_decision pdes"
- " USING (purse_pub)"
- " JOIN account_merges am"
- " ON (am.purse_pub = pm.purse_pub AND"
- " am.reserve_pub = pm.reserve_pub)"
- " WHERE pm.reserve_pub=$1"
- " AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */
- " AND NOT COALESCE (pdes.refunded, FALSE);");
- PREPARE (pg,
- "history_by_reserve",
- "SELECT"
- " history_fee_val"
- ",history_fee_frac"
- ",request_timestamp"
- ",reserve_sig"
- " FROM history_requests"
- " WHERE reserve_pub=$1;");
- PREPARE (pg,
- "open_request_by_reserve",
- "SELECT"
- " reserve_payment_val"
- ",reserve_payment_frac"
- ",request_timestamp"
- ",expiration_date"
- ",requested_purse_limit"
- ",reserve_sig"
- " FROM reserves_open_requests"
- " WHERE reserve_pub=$1;");
- PREPARE (pg,
- "close_request_by_reserve",
- "SELECT"
- " close_timestamp"
- ",payto_uri"
- ",reserve_sig"
- " FROM close_requests"
- " WHERE reserve_pub=$1;");
-
- rhc.reserve_pub = reserve_pub;
- rhc.rh = NULL;
- rhc.rh_tail = NULL;
- rhc.pg = pg;
- rhc.status = GNUNET_OK;
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pg->currency,
- &rhc.balance_in));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pg->currency,
- &rhc.balance_out));
- qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
- for (unsigned int i = 0; NULL != work[i].cb; i++)
+ while (0 < num_results--)
{
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- work[i].statement,
- params,
- work[i].cb,
- &rhc);
- if ( (0 > qs) ||
- (GNUNET_OK != rhc.status) )
+ enum GNUNET_DB_QueryStatus qs;
+ bool found = false;
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ num_results))
+ {
+ GNUNET_break (0);
+ rhc->failed = true;
+ return;
+ }
+
+ for (unsigned int i = 0;
+ NULL != work[i].cb;
+ i++)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to compile reserve history at `%s'\n",
- work[i].statement);
+ if (0 != strcmp (table_name,
+ work[i].table))
+ continue;
+ found = true;
+ qs = GNUNET_PQ_eval_prepared_multi_select (rhc->pg->conn,
+ work[i].statement,
+ params,
+ work[i].cb,
+ rhc);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Reserve %s had %d transactions at %llu in table %s\n",
+ TALER_B2S (rhc->reserve_pub),
+ (int) qs,
+ (unsigned long long) serial_id,
+ table_name);
+ if (0 >= qs)
+ rhc->failed = true;
break;
}
- }
- if ( (qs < 0) ||
- (rhc.status != GNUNET_OK) )
- {
- TEH_COMMON_free_reserve_history (cls,
- rhc.rh);
- rhc.rh = NULL;
- if (qs >= 0)
+ if (! found)
{
- /* status == SYSERR is a very hard error... */
- qs = GNUNET_DB_STATUS_HARD_ERROR;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Coin history includes unsupported table `%s`\n",
+ table_name);
+ rhc->failed = true;
}
+ GNUNET_PQ_cleanup_result (rs);
+ if (rhc->failed)
+ break;
}
- *rhp = rhc.rh;
- GNUNET_assert (0 <=
- TALER_amount_subtract (balance,
- &rhc.balance_in,
- &rhc.balance_out));
- return qs;
}
enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_status (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- struct TALER_Amount *balance_in,
- struct TALER_Amount *balance_out,
- struct TALER_EXCHANGEDB_ReserveHistory **rhp)
+TEH_PG_get_reserve_history (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ uint64_t start_off,
+ uint64_t etag_in,
+ uint64_t *etag_out,
+ struct TALER_Amount *balance,
+ struct TALER_EXCHANGEDB_ReserveHistory **rhp)
{
struct PostgresClosure *pg = cls;
- struct ReserveHistoryContext rhc;
- struct
- {
- /**
- * Name of the prepared statement to run.
- */
- const char *statement;
- /**
- * Function to use to process the results.
- */
- GNUNET_PQ_PostgresResultHandler cb;
- } work[] = {
- /** #TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE */
- { "reserves_in_get_transactions_truncated",
- add_bank_to_exchange },
- /** #TALER_EXCHANGEDB_RO_WITHDRAW_COIN */
- { "get_reserves_out_truncated",
- &add_withdraw_coin },
- /** #TALER_EXCHANGEDB_RO_RECOUP_COIN */
- { "recoup_by_reserve_truncated",
- &add_recoup },
- /** #TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK */
- { "close_by_reserve_truncated",
- &add_exchange_to_bank },
- /** #TALER_EXCHANGEDB_RO_PURSE_MERGE */
- { "merge_by_reserve_truncated",
- &add_p2p_merge },
- /** #TALER_EXCHANGEDB_RO_HISTORY_REQUEST */
- { "history_by_reserve_truncated",
- &add_history_requests },
- /** #TALER_EXCHANGEDB_RO_OPEN_REQUEST */
- { "open_request_by_reserve_truncated",
- &add_open_requests },
- /** #TALER_EXCHANGEDB_RO_CLOSE_REQUEST */
- { "close_request_by_reserve_truncated",
- &add_close_requests },
- /* List terminator */
- { NULL,
- NULL }
+ struct ReserveHistoryContext rhc = {
+ .pg = pg,
+ .reserve_pub = reserve_pub
};
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_TIME_Absolute timelimit;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_absolute_time (&timelimit),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_QueryParam lparams[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_uint64 (&start_off),
GNUNET_PQ_query_param_end
};
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pg->currency,
+ &rhc.balance_in));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (pg->currency,
+ &rhc.balance_out));
+
+ *rhp = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Getting transactions for reserve %s\n",
+ TALER_B2S (reserve_pub));
PREPARE (pg,
- "reserves_in_get_transactions_truncated",
- /*
+ "get_reserve_history_etag",
"SELECT"
- " wire_reference"
- ",credit_val"
- ",credit_frac"
- ",execution_date"
- ",payto_uri AS sender_account_details"
- " FROM reserves_in"
- " JOIN wire_targets"
- " ON (wire_source_h_payto = wire_target_h_payto)"
+ " hist.reserve_history_serial_id"
+ ",r.current_balance"
+ " FROM reserve_history hist"
+ " JOIN reserves r USING (reserve_pub)"
+ " WHERE hist.reserve_pub=$1"
+ " ORDER BY reserve_history_serial_id DESC"
+ " LIMIT 1;");
+ PREPARE (pg,
+ "get_reserve_history",
+ "SELECT"
+ " table_name"
+ ",serial_id"
+ " FROM reserve_history"
" WHERE reserve_pub=$1"
- " AND execution_date>=$2;",
- */
- "WITH ri AS MATERIALIZED ( "
- " SELECT * "
- " FROM reserves_in "
- " WHERE reserve_pub = $1 "
- ") "
- "SELECT "
- " wire_reference "
- " ,credit_val "
- " ,credit_frac "
- " ,execution_date "
- " ,payto_uri AS sender_account_details "
- "FROM wire_targets "
- "JOIN ri "
- " ON (wire_target_h_payto = wire_source_h_payto) "
- "WHERE execution_date >= $2"
- " AND wire_target_h_payto = ( "
- " SELECT wire_source_h_payto FROM ri "
- "); ");
+ " AND reserve_history_serial_id > $2"
+ " ORDER BY reserve_history_serial_id DESC;");
+
PREPARE (pg,
- "get_reserves_out_truncated",
- /*
+ "reserves_in_get_transactions",
+ "SELECT"
+ " ri.wire_reference"
+ ",ri.credit"
+ ",ri.execution_date"
+ ",wt.payto_uri AS sender_account_details"
+ " FROM reserves_in ri"
+ " JOIN wire_targets wt"
+ " ON (wire_source_h_payto = wire_target_h_payto)"
+ " WHERE ri.reserve_pub=$1"
+ " AND ri.reserve_in_serial_id=$2;");
+ PREPARE (pg,
+ "get_reserves_out",
"SELECT"
" ro.h_blind_ev"
",denom.denom_pub_hash"
",ro.denom_sig"
",ro.reserve_sig"
",ro.execution_date"
- ",ro.amount_with_fee_val"
- ",ro.amount_with_fee_frac"
- ",denom.fee_withdraw_val"
- ",denom.fee_withdraw_frac"
- " FROM reserves res"
- " JOIN reserves_out_by_reserve ror"
- " ON (res.reserve_uuid = ror.reserve_uuid)"
- " JOIN reserves_out ro"
- " ON (ro.h_blind_ev = ror.h_blind_ev)"
+ ",ro.amount_with_fee"
+ ",denom.fee_withdraw"
+ " FROM reserves_out ro"
" JOIN denominations denom"
- " ON (ro.denominations_serial = denom.denominations_serial)"
- " WHERE res.reserve_pub=$1"
- " AND execution_date>=$2;",
- */
- "WITH robr AS MATERIALIZED ( "
- " SELECT h_blind_ev "
- " FROM reserves_out_by_reserve "
- " WHERE reserve_uuid= ( "
- " SELECT reserve_uuid "
- " FROM reserves "
- " WHERE reserve_pub = $1 "
- " ) "
- ") SELECT "
- " ro.h_blind_ev "
- " ,denom.denom_pub_hash "
- " ,ro.denom_sig "
- " ,ro.reserve_sig "
- " ,ro.execution_date "
- " ,ro.amount_with_fee_val "
- " ,ro.amount_with_fee_frac "
- " ,denom.fee_withdraw_val "
- " ,denom.fee_withdraw_frac "
- "FROM robr "
- "JOIN reserves_out ro "
- " ON (ro.h_blind_ev = robr.h_blind_ev) "
- "JOIN denominations denom "
- " ON (ro.denominations_serial = denom.denominations_serial)"
- " WHERE ro.execution_date>=$2;");
+ " USING (denominations_serial)"
+ " JOIN reserves res"
+ " USING (reserve_uuid)"
+ " WHERE ro.reserve_out_serial_id=$2"
+ " AND res.reserve_pub=$1;");
PREPARE (pg,
- "recoup_by_reserve_truncated",
- /*
+ "recoup_by_reserve",
"SELECT"
- " recoup.coin_pub"
- ",recoup.coin_sig"
- ",recoup.coin_blind"
- ",recoup.amount_val"
- ",recoup.amount_frac"
- ",recoup.recoup_timestamp"
- ",denominations.denom_pub_hash"
- ",known_coins.denom_sig"
- " FROM denominations"
- " JOIN (known_coins"
- " JOIN recoup "
- " ON (recoup.coin_pub = known_coins.coin_pub))"
- " ON (known_coins.denominations_serial = denominations.denominations_serial)"
- " WHERE recoup_timestamp>=$2"
- " AND recoup.coin_pub"
- " IN (SELECT coin_pub"
- " FROM recoup_by_reserve"
- " JOIN (reserves_out"
- " JOIN (reserves_out_by_reserve"
- " JOIN reserves"
- " ON (reserves.reserve_uuid = reserves_out_by_reserve.reserve_uuid))"
- " ON (reserves_out_by_reserve.h_blind_ev = reserves_out.h_blind_ev))"
- " ON (recoup_by_reserve.reserve_out_serial_id = reserves_out.reserve_out_serial_id)"
- " WHERE reserves.reserve_pub=$1);",
- */
- "SELECT robr.coin_pub "
- " ,robr.coin_sig "
- " ,robr.coin_blind "
- " ,robr.amount_val "
- " ,robr.amount_frac "
- " ,robr.recoup_timestamp "
- " ,denominations.denom_pub_hash "
- " ,robr.denom_sig "
- "FROM denominations "
- " JOIN exchange_do_recoup_by_reserve($1) robr"
- " USING (denominations_serial)"
- " WHERE recoup_timestamp>=$2;");
+ " rec.coin_pub"
+ ",rec.coin_sig"
+ ",rec.coin_blind"
+ ",rec.amount"
+ ",rec.recoup_timestamp"
+ ",denom.denom_pub_hash"
+ ",kc.denom_sig"
+ " FROM recoup rec"
+ " JOIN reserves_out ro"
+ " USING (reserve_out_serial_id)"
+ " JOIN reserves res"
+ " USING (reserve_uuid)"
+ " JOIN known_coins kc"
+ " USING (coin_pub)"
+ " JOIN denominations denom"
+ " ON (denom.denominations_serial = kc.denominations_serial)"
+ " WHERE rec.recoup_uuid=$2"
+ " AND res.reserve_pub=$1;");
PREPARE (pg,
- "close_by_reserve_truncated",
+ "close_by_reserve",
"SELECT"
- " amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",execution_date"
- ",payto_uri AS receiver_account"
- ",wtid"
- " FROM reserves_close"
- " JOIN wire_targets"
- " USING (wire_target_h_payto)"
+ " rc.amount"
+ ",rc.closing_fee"
+ ",rc.execution_date"
+ ",wt.payto_uri AS receiver_account"
+ ",rc.wtid"
+ " FROM reserves_close rc"
+ " JOIN wire_targets wt"
+ " USING (wire_target_h_payto)"
" WHERE reserve_pub=$1"
- " AND execution_date>=$2;");
+ " AND close_uuid=$2;");
PREPARE (pg,
- "merge_by_reserve_truncated",
+ "merge_by_reserve",
"SELECT"
- " pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
- ",pr.balance_val"
- ",pr.balance_frac"
- ",pr.purse_fee_val"
- ",pr.purse_fee_frac"
+ " pr.amount_with_fee"
+ ",pr.balance"
+ ",pr.purse_fee"
",pr.h_contract_terms"
",pr.merge_pub"
",am.reserve_sig"
@@ -1092,97 +809,128 @@ TEH_PG_get_reserve_status (void *cls,
",pr.purse_expiration"
",pr.age_limit"
",pr.flags"
- " FROM purse_merges pm"
+ " FROM purse_decision pdes"
" JOIN purse_requests pr"
- " USING (purse_pub)"
- " JOIN purse_decision pdes"
- " USING (purse_pub)"
+ " ON (pr.purse_pub = pdes.purse_pub)"
+ " JOIN purse_merges pm"
+ " ON (pm.purse_pub = pdes.purse_pub)"
" JOIN account_merges am"
" ON (am.purse_pub = pm.purse_pub AND"
" am.reserve_pub = pm.reserve_pub)"
- " WHERE pm.reserve_pub=$1"
- " AND pm.merge_timestamp >= $2"
+ " WHERE pdes.purse_decision_serial_id=$2"
+ " AND pm.reserve_pub=$1"
" AND COALESCE(pm.partner_serial_id,0)=0" /* must be local! */
" AND NOT pdes.refunded;");
PREPARE (pg,
- "history_by_reserve_truncated",
- "SELECT"
- " history_fee_val"
- ",history_fee_frac"
- ",request_timestamp"
- ",reserve_sig"
- " FROM history_requests"
- " WHERE reserve_pub=$1"
- " AND request_timestamp>=$2;");
- PREPARE (pg,
- "open_request_by_reserve_truncated",
+ "open_request_by_reserve",
"SELECT"
- " reserve_payment_val"
- ",reserve_payment_frac"
+ " reserve_payment"
",request_timestamp"
",expiration_date"
",requested_purse_limit"
",reserve_sig"
" FROM reserves_open_requests"
" WHERE reserve_pub=$1"
- " AND request_timestamp>=$2;");
-
+ " AND open_request_uuid=$2;");
PREPARE (pg,
- "close_request_by_reserve_truncated",
+ "close_request_by_reserve",
"SELECT"
" close_timestamp"
",payto_uri"
",reserve_sig"
" FROM close_requests"
" WHERE reserve_pub=$1"
- " AND close_timestamp>=$2;");
-
- timelimit = GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_get (),
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
- 5));
- rhc.reserve_pub = reserve_pub;
- rhc.rh = NULL;
- rhc.rh_tail = NULL;
- rhc.pg = pg;
- rhc.status = GNUNET_OK;
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pg->currency,
- &rhc.balance_in));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (pg->currency,
- &rhc.balance_out));
- qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* make static analysis happy */
- for (unsigned int i = 0; NULL != work[i].cb; i++)
+ " AND close_request_serial_id=$2;");
+
+ for (unsigned int i = 0; i<RETRIES; i++)
{
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- work[i].statement,
- params,
- work[i].cb,
- &rhc);
- if ( (0 > qs) ||
- (GNUNET_OK != rhc.status) )
+ enum GNUNET_DB_QueryStatus qs;
+ uint64_t end;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("reserve_history_serial_id",
+ &end),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ balance),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ TEH_PG_start_read_committed (pg,
+ "get-reserve-transactions"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ /* First only check the last item, to see if
+ we even need to iterate */
+ qs = GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "get_reserve_history_etag",
+ params,
+ rs);
+ switch (qs)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Query %s failed\n",
- work[i].statement);
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_PG_rollback (pg);
+ continue;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ *etag_out = end;
+ if (end == etag_in)
+ return qs;
+ }
+ /* We indeed need to iterate over the history */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Current ETag for reserve %s is %llu\n",
+ TALER_B2S (reserve_pub),
+ (unsigned long long) end);
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "get_reserve_history",
+ lparams,
+ &handle_history_entry,
+ &rhc);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_PG_rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_PG_rollback (pg);
+ continue;
+ default:
break;
}
- }
- if ( (qs < 0) ||
- (rhc.status != GNUNET_OK) )
- {
- TEH_COMMON_free_reserve_history (cls,
- rhc.rh);
- rhc.rh = NULL;
- if (qs >= 0)
+ if (rhc.failed)
+ {
+ TEH_PG_rollback (pg);
+ TEH_COMMON_free_reserve_history (pg,
+ rhc.rh);
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+ }
+ qs = TEH_PG_commit (pg);
+ switch (qs)
{
- /* status == SYSERR is a very hard error... */
- qs = GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TEH_COMMON_free_reserve_history (pg,
+ rhc.rh);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TEH_COMMON_free_reserve_history (pg,
+ rhc.rh);
+ rhc.rh = NULL;
+ continue;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ *rhp = rhc.rh;
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
}
- *rhp = rhc.rh;
- *balance_in = rhc.balance_in;
- *balance_out = rhc.balance_out;
- return qs;
+ return GNUNET_DB_STATUS_SOFT_ERROR;
}
diff --git a/src/exchangedb/pg_get_reserve_history.h b/src/exchangedb/pg_get_reserve_history.h
index ee47996b2..15765f127 100644
--- a/src/exchangedb/pg_get_reserve_history.h
+++ b/src/exchangedb/pg_get_reserve_history.h
@@ -27,41 +27,31 @@
/**
- * Get all of the transaction history associated with the specified
- * reserve.
+ * Compile a list of (historic) transactions performed with the given reserve
+ * (withdraw, incoming wire, open, close operations). Should return 0 if the @a
+ * reserve_pub is unknown, otherwise determine @a etag_out and if it is past @a
+ * etag_in return the history after @a start_off. @a etag_out should be set
+ * to the last row ID of the given @a reserve_pub in the reserve history table.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @param reserve_pub public key of the reserve
+ * @param start_off maximum starting offset in history to exclude from returning
+ * @param etag_in up to this offset the client already has a response, do not
+ * return anything unless @a etag_out will be larger
+ * @param[out] etag_out set to the latest history offset known for this @a coin_pub
* @param[out] balance set to the reserve balance
* @param[out] rhp set to known transaction history (NULL if reserve is unknown)
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_history (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- struct TALER_Amount *balance,
- struct TALER_EXCHANGEDB_ReserveHistory **rhp);
-
-
-/**
- * Get a truncated transaction history associated with the specified
- * reserve.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param reserve_pub public key of the reserve
- * @param[out] balance_in set to the total of inbound
- * transactions in the returned history
- * @param[out] balance_out set to the total of outbound
- * transactions in the returned history
- * @param[out] rhp set to known transaction history (NULL if reserve is unknown)
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_status (void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- struct TALER_Amount *balance_in,
- struct TALER_Amount *balance_out,
- struct TALER_EXCHANGEDB_ReserveHistory **rhp);
+TEH_PG_get_reserve_history (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ uint64_t start_off,
+ uint64_t etag_in,
+ uint64_t *etag_out,
+ struct TALER_Amount *balance,
+ struct TALER_EXCHANGEDB_ReserveHistory **rhp);
#endif
diff --git a/src/exchangedb/pg_insert_history_request.c b/src/exchangedb/pg_get_signature_for_known_coin.c
index 00270b1a1..06074312f 100644
--- a/src/exchangedb/pg_insert_history_request.c
+++ b/src/exchangedb/pg_get_signature_for_known_coin.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2023 Taler Systems SA
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
@@ -14,53 +14,50 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_insert_history_request.c
- * @brief Implementation of the insert_history_request function for Postgres
- * @author Christian Grothoff
+ * @file exchangedb/pg_get_signature_for_known_coin.c
+ * @brief Implementation of the get_signature_for_known_coin function for Postgres
+ * @author Özgür Kesim
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
-#include "pg_insert_history_request.h"
+#include "pg_get_signature_for_known_coin.h"
#include "pg_helper.h"
-
enum GNUNET_DB_QueryStatus
-TEH_PG_insert_history_request (
+TEH_PG_get_signature_for_known_coin (
void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_ReserveSignatureP *reserve_sig,
- struct GNUNET_TIME_Timestamp request_timestamp,
- const struct TALER_Amount *history_fee,
- bool *balance_ok,
- bool *idempotent)
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_DenominationPublicKey *denom_pub,
+ struct TALER_DenominationSignature *denom_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_auto_from_type (reserve_sig),
- GNUNET_PQ_query_param_timestamp (&request_timestamp),
- TALER_PQ_query_param_amount (history_fee),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("balance_ok",
- balance_ok),
- GNUNET_PQ_result_spec_bool ("idempotent",
- idempotent),
+ TALER_PQ_result_spec_denom_pub ("denom_pub",
+ denom_pub),
+ TALER_PQ_result_spec_denom_sig ("denom_sig",
+ denom_sig),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_insert_history_request() */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Getting denomination and signature for (potentially) known coin %s\n",
+ TALER_B2S (coin_pub));
PREPARE (pg,
- "call_history_request",
+ "get_signature_for_known_coin",
"SELECT"
- " out_balance_ok AS balance_ok"
- " ,out_idempotent AS idempotent"
- " FROM exchange_do_history_request"
- " ($1, $2, $3, $4, $5)");
+ " denominations.denom_pub"
+ ",denom_sig"
+ " FROM known_coins"
+ " JOIN denominations USING (denominations_serial)"
+ " WHERE coin_pub=$1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "call_history_request",
+ "get_signature_for_known_coin",
params,
rs);
}
diff --git a/src/exchangedb/pg_get_signature_for_known_coin.h b/src/exchangedb/pg_get_signature_for_known_coin.h
new file mode 100644
index 000000000..ec389176b
--- /dev/null
+++ b/src/exchangedb/pg_get_signature_for_known_coin.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_signature_for_known_coin.h
+ * @brief implementation of the get_signature_for_known_coin function for Postgres
+ * @author Özgür Kesim
+ */
+#ifndef PG_GET_SIGNATURE_FOR_KNOWN_COIN_H
+#define PG_GET_SIGNATURE_FOR_KNOWN_COIN_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Retrieve the denomination and the corresponding signature for a known coin.
+ *
+ * @param cls the plugin closure
+ * @param coin_pub the public key of the coin to search for
+ * @param[out] denom_pub the denomination of the public key, if coin was present
+ * @param[out] denom_sig the signature with the denomination key of the coin, if coin was present
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_signature_for_known_coin (
+ void *cls,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ struct TALER_DenominationPublicKey *denom_pub,
+ struct TALER_DenominationSignature *denom_sig);
+
+#endif
diff --git a/src/exchangedb/pg_get_unfinished_close_requests.c b/src/exchangedb/pg_get_unfinished_close_requests.c
index fa8abdf8b..990e8e00e 100644
--- a/src/exchangedb/pg_get_unfinished_close_requests.c
+++ b/src/exchangedb/pg_get_unfinished_close_requests.c
@@ -142,8 +142,7 @@ TEH_PG_get_unfinished_close_requests (
" reserve_pub"
" ,close_request_serial_id"
" ,close_timestamp AS expiration_date"
- " ,close_val"
- " ,close_frac"
+ " ,close"
" ,(SELECT payto_uri"
" FROM reserves_in ri"
" JOIN wire_targets wt ON (ri.wire_source_h_payto = wt.wire_target_h_payto)"
diff --git a/src/exchangedb/pg_get_wire_accounts.c b/src/exchangedb/pg_get_wire_accounts.c
index 6986eaef2..9770be719 100644
--- a/src/exchangedb/pg_get_wire_accounts.c
+++ b/src/exchangedb/pg_get_wire_accounts.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2024 Taler Systems SA
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
@@ -66,10 +66,33 @@ get_wire_accounts_cb (void *cls,
for (unsigned int i = 0; i < num_results; i++)
{
char *payto_uri;
+ char *conversion_url = NULL;
+ json_t *debit_restrictions = NULL;
+ json_t *credit_restrictions = NULL;
struct TALER_MasterSignatureP master_sig;
+ char *bank_label = NULL;
+ int64_t priority;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("conversion_url",
+ &conversion_url),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("bank_label",
+ &bank_label),
+ NULL),
+ GNUNET_PQ_result_spec_int64 ("priority",
+ &priority),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("debit_restrictions",
+ &debit_restrictions),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("credit_restrictions",
+ &credit_restrictions),
+ NULL),
GNUNET_PQ_result_spec_auto_from_type ("master_sig",
&master_sig),
GNUNET_PQ_result_spec_end
@@ -84,20 +107,33 @@ get_wire_accounts_cb (void *cls,
ctx->status = GNUNET_SYSERR;
return;
}
+ if (NULL == debit_restrictions)
+ {
+ debit_restrictions = json_array ();
+ GNUNET_assert (NULL != debit_restrictions);
+ }
+ if (NULL == credit_restrictions)
+ {
+ credit_restrictions = json_array ();
+ GNUNET_assert (NULL != credit_restrictions);
+ }
ctx->cb (ctx->cb_cls,
payto_uri,
- &master_sig);
+ conversion_url,
+ debit_restrictions,
+ credit_restrictions,
+ &master_sig,
+ bank_label,
+ priority);
GNUNET_PQ_cleanup_result (rs);
}
}
-
-
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_accounts (void *cls,
- TALER_EXCHANGEDB_WireAccountCallback cb,
- void *cb_cls)
+ TALER_EXCHANGEDB_WireAccountCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GetWireAccountsContext ctx = {
@@ -111,12 +147,17 @@ TEH_PG_get_wire_accounts (void *cls,
enum GNUNET_DB_QueryStatus qs;
PREPARE (pg,
- "get_wire_accounts",
- "SELECT"
- " payto_uri"
- ",master_sig"
- " FROM wire_accounts"
- " WHERE is_active");
+ "get_wire_accounts",
+ "SELECT"
+ " payto_uri"
+ ",conversion_url"
+ ",debit_restrictions"
+ ",credit_restrictions"
+ ",master_sig"
+ ",bank_label"
+ ",priority"
+ " FROM wire_accounts"
+ " WHERE is_active");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"get_wire_accounts",
params,
@@ -125,5 +166,4 @@ TEH_PG_get_wire_accounts (void *cls,
if (GNUNET_OK != ctx.status)
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
-
}
diff --git a/src/exchangedb/pg_get_wire_accounts.h b/src/exchangedb/pg_get_wire_accounts.h
index 4ddda0ed3..f4dc97ce0 100644
--- a/src/exchangedb/pg_get_wire_accounts.h
+++ b/src/exchangedb/pg_get_wire_accounts.h
@@ -36,7 +36,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_accounts (void *cls,
- TALER_EXCHANGEDB_WireAccountCallback cb,
+ TALER_EXCHANGEDB_WireAccountCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_get_wire_fee.c b/src/exchangedb/pg_get_wire_fee.c
index 4b4324766..40f517f28 100644
--- a/src/exchangedb/pg_get_wire_fee.c
+++ b/src/exchangedb/pg_get_wire_fee.c
@@ -27,12 +27,12 @@
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fee (void *cls,
- const char *type,
- struct GNUNET_TIME_Timestamp date,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_WireFeeSet *fees,
- struct TALER_MasterSignatureP *master_sig)
+ const char *type,
+ struct GNUNET_TIME_Timestamp date,
+ struct GNUNET_TIME_Timestamp *start_date,
+ struct GNUNET_TIME_Timestamp *end_date,
+ struct TALER_WireFeeSet *fees,
+ struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -54,23 +54,18 @@ TEH_PG_get_wire_fee (void *cls,
GNUNET_PQ_result_spec_end
};
-
-
- /* Used in #postgres_get_wire_fee() */
- PREPARE(pg,
- "get_wire_fee",
- "SELECT "
- " start_date"
- ",end_date"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",master_sig"
- " FROM wire_fee"
- " WHERE wire_method=$1"
- " AND start_date <= $2"
- " AND end_date > $2;");
+ PREPARE (pg,
+ "get_wire_fee",
+ "SELECT "
+ " start_date"
+ ",end_date"
+ ",wire_fee"
+ ",closing_fee"
+ ",master_sig"
+ " FROM wire_fee"
+ " WHERE wire_method=$1"
+ " AND start_date <= $2"
+ " AND end_date > $2;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_wire_fee",
params,
diff --git a/src/exchangedb/pg_get_wire_fee.h b/src/exchangedb/pg_get_wire_fee.h
index 92107fe30..409a5c48b 100644
--- a/src/exchangedb/pg_get_wire_fee.h
+++ b/src/exchangedb/pg_get_wire_fee.h
@@ -39,11 +39,11 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fee (void *cls,
- const char *type,
- struct GNUNET_TIME_Timestamp date,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_WireFeeSet *fees,
+ const char *type,
+ struct GNUNET_TIME_Timestamp date,
+ struct GNUNET_TIME_Timestamp *start_date,
+ struct GNUNET_TIME_Timestamp *end_date,
+ struct TALER_WireFeeSet *fees,
struct TALER_MasterSignatureP *master_sig);
#endif
diff --git a/src/exchangedb/pg_get_wire_fees.c b/src/exchangedb/pg_get_wire_fees.c
index a83db151d..193ccff6a 100644
--- a/src/exchangedb/pg_get_wire_fees.c
+++ b/src/exchangedb/pg_get_wire_fees.c
@@ -109,9 +109,9 @@ get_wire_fees_cb (void *cls,
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fees (void *cls,
- const char *wire_method,
- TALER_EXCHANGEDB_WireFeeCallback cb,
- void *cb_cls)
+ const char *wire_method,
+ TALER_EXCHANGEDB_WireFeeCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -126,14 +126,11 @@ TEH_PG_get_wire_fees (void *cls,
};
enum GNUNET_DB_QueryStatus qs;
-
PREPARE (pg,
"get_wire_fees",
"SELECT"
- " wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ " wire_fee"
+ ",closing_fee"
",start_date"
",end_date"
",master_sig"
diff --git a/src/exchangedb/pg_get_wire_fees.h b/src/exchangedb/pg_get_wire_fees.h
index 83bacd674..798a514db 100644
--- a/src/exchangedb/pg_get_wire_fees.h
+++ b/src/exchangedb/pg_get_wire_fees.h
@@ -37,8 +37,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_get_wire_fees (void *cls,
- const char *wire_method,
- TALER_EXCHANGEDB_WireFeeCallback cb,
+ const char *wire_method,
+ TALER_EXCHANGEDB_WireFeeCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_get_wire_hash_for_contract.c b/src/exchangedb/pg_get_wire_hash_for_contract.c
new file mode 100644
index 000000000..afd659b18
--- /dev/null
+++ b/src/exchangedb/pg_get_wire_hash_for_contract.c
@@ -0,0 +1,81 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_wire_hash_for_contract.c
+ * @brief Implementation of the get_wire_hash_for_contract function for Postgres
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_exchangedb_plugin.h"
+#include "taler_pq_lib.h"
+#include "pg_get_wire_hash_for_contract.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_wire_hash_for_contract (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ struct TALER_MerchantWireHashP *h_wire)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_end
+ };
+ char *payto_uri;
+ struct TALER_WireSaltP wire_salt;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
+ &wire_salt),
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_PQ_result_spec_end
+ };
+
+ /* check if the necessary records exist and get them */
+ PREPARE (pg,
+ "get_wire_hash_for_contract",
+ "SELECT"
+ " bdep.wire_salt"
+ ",wt.payto_uri"
+ " FROM coin_deposits"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
+ " JOIN wire_targets wt"
+ " USING (wire_target_h_payto)"
+ " WHERE bdep.merchant_pub=$1"
+ " AND bdep.h_contract_terms=$2");
+ /* NOTE: above query might be more efficient if we computed the shard
+ from the merchant_pub and included that in the query */
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_wire_hash_for_contract",
+ params,
+ rs);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ TALER_merchant_wire_signature_hash (payto_uri,
+ &wire_salt,
+ h_wire);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+ return qs;
+}
diff --git a/src/exchangedb/pg_get_wire_hash_for_contract.h b/src/exchangedb/pg_get_wire_hash_for_contract.h
new file mode 100644
index 000000000..f95cd29c1
--- /dev/null
+++ b/src/exchangedb/pg_get_wire_hash_for_contract.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_get_wire_hash_for_contract.h
+ * @brief implementation of the get_wire_hash_for_contract function for Postgres
+ * @author Özgür Kesim
+ */
+#ifndef PG_GET_WIRE_HASH_FOR_CONTRACT_H
+#define PG_GET_WIRE_HASH_FOR_CONTRACT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Try to get the salted hash of a merchant's bank account to a deposit
+ * contract. This is necessary in the event of a conflict with a given
+ * (merchant_pub, h_contract_terms) during deposit.
+ *
+ * @param cls closure
+ * @param merchant_pub merchant public key
+ * @param h_contract_terms hash of the proposal data
+ * @param[out] h_wire salted hash of a merchant's bank account
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_wire_hash_for_contract (
+ void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ struct TALER_MerchantWireHashP *h_wire);
+
+#endif
diff --git a/src/exchangedb/pg_get_withdraw_info.c b/src/exchangedb/pg_get_withdraw_info.c
index ef3936269..e06fa3764 100644
--- a/src/exchangedb/pg_get_withdraw_info.c
+++ b/src/exchangedb/pg_get_withdraw_info.c
@@ -55,10 +55,6 @@ TEH_PG_get_withdraw_info (
GNUNET_PQ_result_spec_end
};
- /* 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 (pg,
"get_withdraw_info",
"SELECT"
@@ -68,10 +64,8 @@ TEH_PG_get_withdraw_info (
",reserves.reserve_pub"
",execution_date"
",h_blind_ev"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",denom.fee_withdraw_val"
- ",denom.fee_withdraw_frac"
+ ",amount_with_fee"
+ ",denom.fee_withdraw"
" FROM reserves_out"
" JOIN reserves"
" USING (reserve_uuid)"
diff --git a/src/exchangedb/pg_have_deposit2.c b/src/exchangedb/pg_have_deposit2.c
index 1616858c5..e00ad7490 100644
--- a/src/exchangedb/pg_have_deposit2.c
+++ b/src/exchangedb/pg_have_deposit2.c
@@ -70,31 +70,28 @@ TEH_PG_have_deposit2 (
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Getting deposits for coin %s\n",
TALER_B2S (coin_pub));
-
- /* Fetch an existing deposit request, used to ensure idempotency
- during /deposit processing. Used in #postgres_have_deposit(). */
PREPARE (pg,
- "get_deposit",
- "SELECT"
- " dep.amount_with_fee_val"
- ",dep.amount_with_fee_frac"
- ",denominations.fee_deposit_val"
- ",denominations.fee_deposit_frac"
- ",dep.wallet_timestamp"
- ",dep.exchange_timestamp"
- ",dep.refund_deadline"
- ",dep.wire_deadline"
- ",dep.h_contract_terms"
- ",dep.wire_salt"
- ",wt.payto_uri AS receiver_wire_account"
- " FROM deposits dep"
- " JOIN known_coins kc ON (kc.coin_pub = dep.coin_pub)"
- " JOIN denominations USING (denominations_serial)"
- " JOIN wire_targets wt USING (wire_target_h_payto)"
- " WHERE dep.coin_pub=$1"
- " AND dep.merchant_pub=$3"
- " AND dep.h_contract_terms=$2;");
-
+ "get_deposit",
+ "SELECT"
+ " cdep.amount_with_fee"
+ ",denominations.fee_deposit"
+ ",bdep.wallet_timestamp"
+ ",bdep.exchange_timestamp"
+ ",bdep.refund_deadline"
+ ",bdep.wire_deadline"
+ ",bdep.h_contract_terms"
+ ",bdep.wire_salt"
+ ",wt.payto_uri AS receiver_wire_account"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep USING (batch_deposit_serial_id)"
+ " JOIN known_coins kc ON (kc.coin_pub = cdep.coin_pub)"
+ " JOIN denominations USING (denominations_serial)"
+ " JOIN wire_targets wt USING (wire_target_h_payto)"
+ " WHERE cdep.coin_pub=$1"
+ " AND bdep.merchant_pub=$3"
+ " AND bdep.h_contract_terms=$2;");
+ /* Note: query might be made more efficient if we computed the 'shard'
+ from merchant_pub and included that as a constraint on bdep! */
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_deposit",
params,
diff --git a/src/exchangedb/pg_helper.h b/src/exchangedb/pg_helper.h
index 512f75056..c63c9111d 100644
--- a/src/exchangedb/pg_helper.h
+++ b/src/exchangedb/pg_helper.h
@@ -141,19 +141,8 @@ struct PostgresClosure
* @param field name of the database field to fetch amount from
* @param[out] amountp pointer to amount to set
*/
-#define TALER_PQ_RESULT_SPEC_AMOUNT(field,amountp) TALER_PQ_result_spec_amount ( \
- field,pg->currency,amountp)
-
-
-/**
- * Wrapper macro to add the currency from the plugin's state
- * when fetching amounts from the database. NBO variant.
- *
- * @param field name of the database field to fetch amount from
- * @param[out] amountp pointer to amount to set
- */
-#define TALER_PQ_RESULT_SPEC_AMOUNT_NBO(field, \
- amountp) TALER_PQ_result_spec_amount_nbo ( \
+#define TALER_PQ_RESULT_SPEC_AMOUNT(field, \
+ amountp) TALER_PQ_result_spec_amount ( \
field,pg->currency,amountp)
diff --git a/src/exchangedb/pg_inject_auditor_triggers.c b/src/exchangedb/pg_inject_auditor_triggers.c
new file mode 100644
index 000000000..562a1a22c
--- /dev/null
+++ b/src/exchangedb/pg_inject_auditor_triggers.c
@@ -0,0 +1,57 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_inject_auditor_triggers.c
+ * @brief Implementation of the inject_auditor_triggers function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_gc.h"
+#include "pg_helper.h"
+
+
+/**
+ * Function called to inject auditor triggers into the
+ * database, triggering the real-time auditor upon
+ * relevant INSERTs.
+ *
+ * @param cls closure
+ * @return #GNUNET_OK on success,
+ * #GNUNET_SYSERR on DB errors
+ */
+enum GNUNET_GenericReturnValue
+TEH_PG_inject_auditor_triggers (void *cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_Context *conn;
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+ "exchangedb-postgres",
+ "auditor-triggers-",
+ es,
+ NULL);
+ if (NULL == conn)
+ return GNUNET_SYSERR;
+ GNUNET_PQ_disconnect (conn);
+ return GNUNET_OK;
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h b/src/exchangedb/pg_inject_auditor_triggers.h
index 4f0ac1aae..2dfa9468c 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_inject_auditor_triggers.h
@@ -14,30 +14,28 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for Postgres
+ * @file exchangedb/pg_inject_auditor_triggers.h
+ * @brief implementation of the inject_auditor_triggers function for Postgres
* @author Christian Grothoff
*/
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INJECT_AUDITOR_TRIGGERS_H
+#define PG_INJECT_AUDITOR_TRIGGERS_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
- * Function called to insert aggregation information into the DB.
+ * Function called to inject auditor triggers into the
+ * database, triggering the real-time auditor upon
+ * relevant INSERTs.
*
* @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is aggregation data
- * @return transaction status code
+ * @return #GNUNET_OK on success,
+ * #GNUNET_SYSERR on DB errors
*/
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
- void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- unsigned long long deposit_serial_id);
+enum GNUNET_GenericReturnValue
+TEH_PG_inject_auditor_triggers (void *cls);
-#endif
+#endif
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.c b/src/exchangedb/pg_insert_aggregation_tracking.c
deleted file mode 100644
index 01c5928ba..000000000
--- a/src/exchangedb/pg_insert_aggregation_tracking.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_insert_aggregation_tracking.c
- * @brief Implementation of the insert_aggregation_tracking function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_insert_aggregation_tracking.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
- void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- unsigned long long deposit_serial_id)
-{
- struct PostgresClosure *pg = cls;
- uint64_t rid = deposit_serial_id;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&rid),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
-
- PREPARE (pg,
- "insert_aggregation_tracking",
- "INSERT INTO aggregation_tracking "
- "(deposit_serial_id"
- ",wtid_raw"
- ") VALUES "
- "($1, $2);");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_aggregation_tracking",
- params);
-}
-
diff --git a/src/exchangedb/pg_insert_aml_decision.c b/src/exchangedb/pg_insert_aml_decision.c
index 85570ed85..39419be59 100644
--- a/src/exchangedb/pg_insert_aml_decision.c
+++ b/src/exchangedb/pg_insert_aml_decision.c
@@ -24,6 +24,7 @@
#include "taler_pq_lib.h"
#include "pg_insert_aml_decision.h"
#include "pg_helper.h"
+#include <gnunet/gnunet_pq_lib.h>
enum GNUNET_DB_QueryStatus
@@ -34,6 +35,8 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time,
const char *justification,
+ const json_t *kyc_requirements,
+ uint64_t requirements_row,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
@@ -41,14 +44,29 @@ TEH_PG_insert_aml_decision (
{
struct PostgresClosure *pg = cls;
uint32_t ns = (uint32_t) new_status;
+ struct TALER_KycCompletedEventP rep = {
+ .header.size = htons (sizeof (rep)),
+ .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
+ .h_payto = *h_payto
+ };
+ char *notify_s = GNUNET_PQ_get_event_notify_channel (&rep.header);
+ char *kyc_s = (NULL != kyc_requirements)
+ ? json_dumps (kyc_requirements, JSON_COMPACT)
+ : NULL;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
- TALER_PQ_query_param_amount (new_threshold),
+ TALER_PQ_query_param_amount (pg->conn,
+ new_threshold),
GNUNET_PQ_query_param_uint32 (&ns),
GNUNET_PQ_query_param_timestamp (&decision_time),
GNUNET_PQ_query_param_string (justification),
GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig),
+ GNUNET_PQ_query_param_string (notify_s),
+ NULL != kyc_requirements
+ ? GNUNET_PQ_query_param_string (kyc_s)
+ : GNUNET_PQ_query_param_null (),
+ GNUNET_PQ_query_param_uint64 (&requirements_row),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -58,6 +76,7 @@ TEH_PG_insert_aml_decision (
last_date),
GNUNET_PQ_result_spec_end
};
+ enum GNUNET_DB_QueryStatus qs;
PREPARE (pg,
"do_insert_aml_decision",
@@ -65,9 +84,14 @@ TEH_PG_insert_aml_decision (
" out_invalid_officer"
",out_last_date"
" FROM exchange_do_insert_aml_decision"
- "($1, $2, $3, $4, $5, $6, $7, $8);");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "do_insert_aml_decision",
- params,
- rs);
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "do_insert_aml_decision",
+ params,
+ rs);
+ GNUNET_free (notify_s);
+ GNUNET_PQ_event_do_poll (pg->conn);
+ if (NULL != kyc_s)
+ free (kyc_s);
+ return qs;
}
diff --git a/src/exchangedb/pg_insert_aml_decision.h b/src/exchangedb/pg_insert_aml_decision.h
index b539945a7..073a2f50a 100644
--- a/src/exchangedb/pg_insert_aml_decision.h
+++ b/src/exchangedb/pg_insert_aml_decision.h
@@ -36,6 +36,8 @@
* @param new_status AML decision status
* @param decision_time when was the decision made
* @param justification human-readable text justifying the decision
+ * @param kyc_requirements JSON array with KYC requirements
+ * @param requirements_row row in the KYC table for this process, 0 for none
* @param decider_pub public key of the staff member
* @param decider_sig signature of the staff member
* @param[out] invalid_officer set to TRUE if @a decider_pub is not allowed to make decisions right now
@@ -51,6 +53,8 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time,
const char *justification,
+ const json_t *kyc_requirements,
+ uint64_t requirements_row,
const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer,
diff --git a/src/exchangedb/pg_insert_auditor.c b/src/exchangedb/pg_insert_auditor.c
index 757dfa625..2f1de7ba7 100644
--- a/src/exchangedb/pg_insert_auditor.c
+++ b/src/exchangedb/pg_insert_auditor.c
@@ -27,10 +27,10 @@
enum GNUNET_DB_QueryStatus
TEH_PG_insert_auditor (void *cls,
- const struct TALER_AuditorPublicKeyP *auditor_pub,
- const char *auditor_url,
- const char *auditor_name,
- struct GNUNET_TIME_Timestamp start_date)
+ const struct TALER_AuditorPublicKeyP *auditor_pub,
+ const char *auditor_url,
+ const char *auditor_name,
+ struct GNUNET_TIME_Timestamp start_date)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -41,7 +41,7 @@ TEH_PG_insert_auditor (void *cls,
GNUNET_PQ_query_param_end
};
- /* used in #postgres_insert_auditor() */
+ /* used in #postgres_insert_auditor() */
PREPARE (pg,
"insert_auditor",
"INSERT INTO auditors "
diff --git a/src/exchangedb/pg_insert_auditor.h b/src/exchangedb/pg_insert_auditor.h
index 7523282e4..8de388f23 100644
--- a/src/exchangedb/pg_insert_auditor.h
+++ b/src/exchangedb/pg_insert_auditor.h
@@ -38,8 +38,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_auditor (void *cls,
- const struct TALER_AuditorPublicKeyP *auditor_pub,
- const char *auditor_url,
- const char *auditor_name,
+ const struct TALER_AuditorPublicKeyP *auditor_pub,
+ const char *auditor_url,
+ const char *auditor_name,
struct GNUNET_TIME_Timestamp start_date);
#endif
diff --git a/src/exchangedb/pg_insert_close_request.c b/src/exchangedb/pg_insert_close_request.c
index 387dafd9a..b4bc5f4a7 100644
--- a/src/exchangedb/pg_insert_close_request.c
+++ b/src/exchangedb/pg_insert_close_request.c
@@ -41,8 +41,10 @@ TEH_PG_insert_close_request (
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_timestamp (&request_timestamp),
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
- TALER_PQ_query_param_amount (balance),
- TALER_PQ_query_param_amount (closing_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ balance),
+ TALER_PQ_query_param_amount (pg->conn,
+ closing_fee),
GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_end
};
@@ -53,14 +55,12 @@ TEH_PG_insert_close_request (
"(reserve_pub"
",close_timestamp"
",reserve_sig"
- ",close_val"
- ",close_frac"
- ",close_fee_val"
- ",close_fee_frac"
+ ",close"
+ ",close_fee"
",payto_uri"
")"
"VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8)"
+ "($1, $2, $3, $4, $5, $6)"
" ON CONFLICT DO NOTHING;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_account_close",
diff --git a/src/exchangedb/pg_insert_contract.c b/src/exchangedb/pg_insert_contract.c
index d3e6c23be..0274f8d93 100644
--- a/src/exchangedb/pg_insert_contract.c
+++ b/src/exchangedb/pg_insert_contract.c
@@ -45,20 +45,20 @@ TEH_PG_insert_contract (
};
*in_conflict = false;
- /* Used in #postgres_insert_contract() */
+ /* Used in #postgres_insert_contract() */
PREPARE (pg,
- "insert_contract",
- "INSERT INTO contracts"
- " (purse_pub"
- " ,pub_ckey"
- " ,e_contract"
- " ,contract_sig"
- " ,purse_expiration"
- " ) SELECT "
- " $1, $2, $3, $4, purse_expiration"
- " FROM purse_requests"
- " WHERE purse_pub=$1"
- " ON CONFLICT DO NOTHING;");
+ "insert_contract",
+ "INSERT INTO contracts"
+ " (purse_pub"
+ " ,pub_ckey"
+ " ,e_contract"
+ " ,contract_sig"
+ " ,purse_expiration"
+ " ) SELECT "
+ " $1, $2, $3, $4, purse_expiration"
+ " FROM purse_requests"
+ " WHERE purse_pub=$1"
+ " ON CONFLICT DO NOTHING;");
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_contract",
params);
@@ -68,8 +68,8 @@ TEH_PG_insert_contract (
struct TALER_EncryptedContract econtract2;
qs = TEH_PG_select_contract_by_purse (pg,
- purse_pub,
- &econtract2);
+ purse_pub,
+ &econtract2);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
GNUNET_break (0);
diff --git a/src/exchangedb/pg_insert_denomination_info.c b/src/exchangedb/pg_insert_denomination_info.c
index 301996116..878bc5d81 100644
--- a/src/exchangedb/pg_insert_denomination_info.c
+++ b/src/exchangedb/pg_insert_denomination_info.c
@@ -42,11 +42,16 @@ TEH_PG_insert_denomination_info (
GNUNET_PQ_query_param_timestamp (&issue->expire_withdraw),
GNUNET_PQ_query_param_timestamp (&issue->expire_deposit),
GNUNET_PQ_query_param_timestamp (&issue->expire_legal),
- TALER_PQ_query_param_amount (&issue->value),
- TALER_PQ_query_param_amount (&issue->fees.withdraw),
- TALER_PQ_query_param_amount (&issue->fees.deposit),
- TALER_PQ_query_param_amount (&issue->fees.refresh),
- TALER_PQ_query_param_amount (&issue->fees.refund),
+ TALER_PQ_query_param_amount (pg->conn,
+ &issue->value),
+ TALER_PQ_query_param_amount (pg->conn,
+ &issue->fees.withdraw),
+ TALER_PQ_query_param_amount (pg->conn,
+ &issue->fees.deposit),
+ TALER_PQ_query_param_amount (pg->conn,
+ &issue->fees.refresh),
+ TALER_PQ_query_param_amount (pg->conn,
+ &issue->fees.refund),
GNUNET_PQ_query_param_uint32 (&denom_pub->age_mask.bits),
GNUNET_PQ_query_param_end
};
@@ -81,20 +86,15 @@ TEH_PG_insert_denomination_info (
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin" /* value of this denom */
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",age_mask"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17, $18);");
+ " $11, $12, $13);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"denomination_insert",
params);
diff --git a/src/exchangedb/pg_insert_denomination_revocation.c b/src/exchangedb/pg_insert_denomination_revocation.c
index 061d7adc0..49445f262 100644
--- a/src/exchangedb/pg_insert_denomination_revocation.c
+++ b/src/exchangedb/pg_insert_denomination_revocation.c
@@ -39,7 +39,7 @@ TEH_PG_insert_denomination_revocation (
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_insert_denomination_revocation() */
+ /* Used in #postgres_insert_denomination_revocation() */
PREPARE (pg,
"denomination_revocation_insert",
"INSERT INTO denomination_revocations "
diff --git a/src/exchangedb/pg_insert_deposit.c b/src/exchangedb/pg_insert_deposit.c
deleted file mode 100644
index ec4d49bf9..000000000
--- a/src/exchangedb/pg_insert_deposit.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_insert_deposit.c
- * @brief Implementation of the insert_deposit function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_insert_deposit.h"
-#include "pg_helper.h"
-#include "pg_setup_wire_target.h"
-#include "pg_compute_shard.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_deposit (void *cls,
- struct GNUNET_TIME_Timestamp exchange_timestamp,
- const struct TALER_EXCHANGEDB_Deposit *deposit)
-{
- struct PostgresClosure *pg = cls;
- struct TALER_PaytoHashP h_payto;
- enum GNUNET_DB_QueryStatus qs;
-
- qs = TEH_PG_setup_wire_target (pg,
- deposit->receiver_wire_account,
- &h_payto);
- if (qs < 0)
- return qs;
- if (GNUNET_TIME_timestamp_cmp (deposit->wire_deadline,
- <,
- deposit->refund_deadline))
- {
- GNUNET_break (0);
- }
- {
- uint64_t shard = TEH_PG_compute_shard (&deposit->merchant_pub);
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
- TALER_PQ_query_param_amount (&deposit->amount_with_fee),
- GNUNET_PQ_query_param_timestamp (&deposit->timestamp),
- GNUNET_PQ_query_param_timestamp (&deposit->refund_deadline),
- GNUNET_PQ_query_param_timestamp (&deposit->wire_deadline),
- GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&deposit->wire_salt),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
- GNUNET_PQ_query_param_timestamp (&exchange_timestamp),
- GNUNET_PQ_query_param_uint64 (&shard),
- GNUNET_PQ_query_param_end
- };
-
- GNUNET_assert (shard <= INT32_MAX);
- GNUNET_log (
- GNUNET_ERROR_TYPE_INFO,
- "Inserting deposit to be executed at %s (%llu/%llu)\n",
- GNUNET_TIME_timestamp2s (deposit->wire_deadline),
- (unsigned long long) deposit->wire_deadline.abs_time.abs_value_us,
- (unsigned long long) deposit->refund_deadline.abs_time.abs_value_us);
- /* Store information about a /deposit the exchange is to execute.
- Used in #postgres_insert_deposit(). Only used in test cases. */
- PREPARE (pg,
- "insert_deposit",
- "INSERT INTO deposits "
- "(known_coin_id"
- ",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wallet_timestamp"
- ",refund_deadline"
- ",wire_deadline"
- ",merchant_pub"
- ",h_contract_terms"
- ",wire_salt"
- ",wire_target_h_payto"
- ",coin_sig"
- ",exchange_timestamp"
- ",shard"
- ") SELECT known_coin_id, $1, $2, $3, $4, $5, $6, "
- " $7, $8, $9, $10, $11, $12, $13"
- " FROM known_coins"
- " WHERE coin_pub=$1"
- " ON CONFLICT DO NOTHING;");
-
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_deposit",
- params);
- }
-}
diff --git a/src/exchangedb/pg_insert_drain_profit.c b/src/exchangedb/pg_insert_drain_profit.c
index 19340eafb..a0de02e9b 100644
--- a/src/exchangedb/pg_insert_drain_profit.c
+++ b/src/exchangedb/pg_insert_drain_profit.c
@@ -41,11 +41,12 @@ TEH_PG_insert_drain_profit (
GNUNET_PQ_query_param_string (account_section),
GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_timestamp (&request_timestamp),
- TALER_PQ_query_param_amount (amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount),
GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_insert_drain_profit() */
+
PREPARE (pg,
"drain_profit_insert",
"INSERT INTO profit_drains "
@@ -53,11 +54,9 @@ TEH_PG_insert_drain_profit (
",account_section"
",payto_uri"
",trigger_date"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",master_sig"
- ") VALUES ($1, $2, $3, $4, $5, $6, $7);");
-
+ ") VALUES ($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"drain_profit_insert",
params);
diff --git a/src/exchangedb/pg_insert_global_fee.c b/src/exchangedb/pg_insert_global_fee.c
index c08fc23bb..e78cd0b83 100644
--- a/src/exchangedb/pg_insert_global_fee.c
+++ b/src/exchangedb/pg_insert_global_fee.c
@@ -28,21 +28,24 @@
enum GNUNET_DB_QueryStatus
TEH_PG_insert_global_fee (void *cls,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_GlobalFeeSet *fees,
- struct GNUNET_TIME_Relative purse_timeout,
- struct GNUNET_TIME_Relative history_expiration,
- uint32_t purse_account_limit,
- const struct TALER_MasterSignatureP *master_sig)
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_GlobalFeeSet *fees,
+ struct GNUNET_TIME_Relative purse_timeout,
+ struct GNUNET_TIME_Relative history_expiration,
+ uint32_t purse_account_limit,
+ const struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_timestamp (&start_date),
GNUNET_PQ_query_param_timestamp (&end_date),
- TALER_PQ_query_param_amount (&fees->history),
- TALER_PQ_query_param_amount (&fees->account),
- TALER_PQ_query_param_amount (&fees->purse),
+ TALER_PQ_query_param_amount (pg->conn,
+ &fees->history),
+ TALER_PQ_query_param_amount (pg->conn,
+ &fees->account),
+ TALER_PQ_query_param_amount (pg->conn,
+ &fees->purse),
GNUNET_PQ_query_param_relative_time (&purse_timeout),
GNUNET_PQ_query_param_relative_time (&history_expiration),
GNUNET_PQ_query_param_uint32 (&purse_account_limit),
@@ -59,14 +62,14 @@ TEH_PG_insert_global_fee (void *cls,
uint32_t pal;
qs = TEH_PG_get_global_fee (pg,
- start_date,
- &sd,
- &ed,
- &wx,
- &pt,
- &he,
- &pal,
- &sig);
+ start_date,
+ &sd,
+ &ed,
+ &wx,
+ &pt,
+ &he,
+ &pal,
+ &sig);
if (qs < 0)
return qs;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
@@ -113,24 +116,21 @@ TEH_PG_insert_global_fee (void *cls,
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
- /* Used in #postgres_insert_global_fee */
+ /* Used in #postgres_insert_global_fee */
PREPARE (pg,
"insert_global_fee",
"INSERT INTO global_fee "
"(start_date"
",end_date"
- ",history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",history_fee"
+ ",account_fee"
+ ",purse_fee"
",purse_timeout"
",history_expiration"
",purse_account_limit"
",master_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_global_fee",
params);
diff --git a/src/exchangedb/pg_insert_global_fee.h b/src/exchangedb/pg_insert_global_fee.h
index 9780d5322..411345dc4 100644
--- a/src/exchangedb/pg_insert_global_fee.h
+++ b/src/exchangedb/pg_insert_global_fee.h
@@ -40,11 +40,11 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_global_fee (void *cls,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_GlobalFeeSet *fees,
- struct GNUNET_TIME_Relative purse_timeout,
- struct GNUNET_TIME_Relative history_expiration,
- uint32_t purse_account_limit,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_GlobalFeeSet *fees,
+ struct GNUNET_TIME_Relative purse_timeout,
+ struct GNUNET_TIME_Relative history_expiration,
+ uint32_t purse_account_limit,
const struct TALER_MasterSignatureP *master_sig);
#endif
diff --git a/src/exchangedb/pg_insert_history_request.h b/src/exchangedb/pg_insert_history_request.h
deleted file mode 100644
index 75004a7e4..000000000
--- a/src/exchangedb/pg_insert_history_request.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_insert_history_request.h
- * @brief implementation of the insert_history_request function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_INSERT_HISTORY_REQUEST_H
-#define PG_INSERT_HISTORY_REQUEST_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Function called to persist a signature that
- * prove that the client requested an
- * account history. Debits the @a history_fee from
- * the reserve (if possible).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param reserve_pub account that the history was requested for
- * @param reserve_sig signature affirming the request
- * @param request_timestamp when was the request made
- * @param history_fee how much should the @a reserve_pub be charged for the request
- * @param[out] balance_ok set to TRUE if the reserve balance
- * was sufficient
- * @param[out] idempotent set to TRUE if the request is already in the DB
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_insert_history_request (
- void *cls,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_ReserveSignatureP *reserve_sig,
- struct GNUNET_TIME_Timestamp request_timestamp,
- const struct TALER_Amount *history_fee,
- bool *balance_ok,
- bool *idempotent);
-
-#endif
diff --git a/src/exchangedb/pg_insert_kyc_attributes.c b/src/exchangedb/pg_insert_kyc_attributes.c
index fd90950fd..3c94abb85 100644
--- a/src/exchangedb/pg_insert_kyc_attributes.c
+++ b/src/exchangedb/pg_insert_kyc_attributes.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023 Taler Systems SA
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
@@ -29,43 +29,82 @@
enum GNUNET_DB_QueryStatus
TEH_PG_insert_kyc_attributes (
void *cls,
+ uint64_t process_row,
const struct TALER_PaytoHashP *h_payto,
const struct GNUNET_ShortHashCode *kyc_prox,
const char *provider_section,
- const char *birthdate,
+ unsigned int num_checks,
+ const char *satisfied_checks[static num_checks],
+ uint32_t birthday,
struct GNUNET_TIME_Timestamp collection_time,
- struct GNUNET_TIME_Timestamp expiration_time,
+ const char *provider_account_id,
+ const char *provider_legitimization_id,
+ struct GNUNET_TIME_Absolute expiration_time,
size_t enc_attributes_size,
- const void *enc_attributes)
+ const void *enc_attributes,
+ bool require_aml)
{
struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Timestamp expiration
+ = GNUNET_TIME_absolute_to_timestamp (expiration_time);
+ struct TALER_KycCompletedEventP rep = {
+ .header.size = htons (sizeof (rep)),
+ .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
+ .h_payto = *h_payto
+ };
+ char *kyc_completed_notify_s
+ = GNUNET_PQ_get_event_notify_channel (&rep.header);
struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&process_row),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_auto_from_type (kyc_prox),
GNUNET_PQ_query_param_string (provider_section),
- (NULL == birthdate)
+ GNUNET_PQ_query_param_array_ptrs_string (num_checks,
+ satisfied_checks,
+ pg->conn),
+ GNUNET_PQ_query_param_uint32 (&birthday),
+ (NULL == provider_account_id)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (provider_account_id),
+ (NULL == provider_legitimization_id)
? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (birthdate),
+ : GNUNET_PQ_query_param_string (provider_legitimization_id),
GNUNET_PQ_query_param_timestamp (&collection_time),
- GNUNET_PQ_query_param_timestamp (&expiration_time),
+ GNUNET_PQ_query_param_absolute_time (&expiration_time),
+ GNUNET_PQ_query_param_timestamp (&expiration),
GNUNET_PQ_query_param_fixed_size (enc_attributes,
enc_attributes_size),
+ GNUNET_PQ_query_param_bool (require_aml),
+ GNUNET_PQ_query_param_string (kyc_completed_notify_s),
GNUNET_PQ_query_param_end
};
+ bool ok;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("out_ok",
+ &ok),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Inserting KYC attributes, wake up on %s\n",
+ kyc_completed_notify_s);
PREPARE (pg,
"insert_kyc_attributes",
- "INSERT INTO kyc_attributes "
- "(h_payto"
- ",kyc_prox"
- ",provider"
- ",birthdate"
- ",collection_time"
- ",expiration_time"
- ",encrypted_attributes"
- ") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_kyc_attributes",
- params);
+ "SELECT "
+ " out_ok"
+ " FROM exchange_do_insert_kyc_attributes "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "insert_kyc_attributes",
+ params,
+ rs);
+ GNUNET_PQ_cleanup_query_params_closures (params);
+ GNUNET_free (kyc_completed_notify_s);
+ GNUNET_PQ_event_do_poll (pg->conn);
+ if (qs < 0)
+ return qs;
+ if (! ok)
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ return qs;
}
diff --git a/src/exchangedb/pg_insert_kyc_attributes.h b/src/exchangedb/pg_insert_kyc_attributes.h
index 8ee307d7d..35b25bdc8 100644
--- a/src/exchangedb/pg_insert_kyc_attributes.h
+++ b/src/exchangedb/pg_insert_kyc_attributes.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023 Taler Systems SA
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
@@ -27,30 +27,43 @@
/**
- * Store KYC attribute data.
+ * Store KYC attribute data, update KYC process status and
+ * AML status for the given account.
*
* @param cls closure
+ * @param process_row KYC process row to update
* @param h_payto account for which the attribute data is stored
* @param kyc_prox key for similarity search
* @param provider_section provider that must be checked
- * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
- * digits can be 0 if exact day, month or year are unknown
+ * @param num_checks how many checks do these attributes satisfy
+ * @param satisfied_checks array of checks satisfied by these attributes
+ * @param provider_account_id provider account ID
+ * @param provider_legitimization_id provider legitimization ID
+ * @param birthday birthdate of user, in days after 1990, or 0 if unknown or definitively adult
* @param collection_time when was the data collected
* @param expiration_time when does the data expire
* @param enc_attributes_size number of bytes in @a enc_attributes
* @param enc_attributes encrypted attribute data
+ * @param require_aml true to trigger AML
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_kyc_attributes (
void *cls,
+ uint64_t process_row,
const struct TALER_PaytoHashP *h_payto,
const struct GNUNET_ShortHashCode *kyc_prox,
const char *provider_section,
- const char *birthdate,
+ unsigned int num_checks,
+ const char *satisfied_checks[static num_checks],
+ uint32_t birthday,
struct GNUNET_TIME_Timestamp collection_time,
- struct GNUNET_TIME_Timestamp expiration_time,
+ const char *provider_account_id,
+ const char *provider_legitimization_id,
+ struct GNUNET_TIME_Absolute expiration_time,
size_t enc_attributes_size,
- const void *enc_attributes);
+ const void *enc_attributes,
+ bool require_aml);
+
#endif
diff --git a/src/exchangedb/pg_insert_kyc_failure.c b/src/exchangedb/pg_insert_kyc_failure.c
new file mode 100644
index 000000000..568c39ca8
--- /dev/null
+++ b/src/exchangedb/pg_insert_kyc_failure.c
@@ -0,0 +1,82 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_insert_kyc_failure.c
+ * @brief Implementation of the insert_kyc_failure function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_kyc_failure.h"
+#include "pg_helper.h"
+#include "pg_event_notify.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_kyc_failure (
+ void *cls,
+ uint64_t process_row,
+ const struct TALER_PaytoHashP *h_payto,
+ const char *provider_section,
+ const char *provider_account_id,
+ const char *provider_legitimization_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&process_row),
+ GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_string (provider_section),
+ NULL != provider_account_id
+ ? GNUNET_PQ_query_param_string (provider_account_id)
+ : GNUNET_PQ_query_param_null (),
+ NULL != provider_legitimization_id
+ ? GNUNET_PQ_query_param_string (provider_legitimization_id)
+ : GNUNET_PQ_query_param_null (),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "insert_kyc_failure",
+ "UPDATE legitimization_processes"
+ " SET"
+ " finished=TRUE"
+ " ,provider_user_id=$4"
+ " ,provider_legitimization_id=$5"
+ " WHERE h_payto=$2"
+ " AND legitimization_process_serial_id=$1"
+ " AND provider_section=$3;");
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_kyc_failure",
+ params);
+ if (qs > 0)
+ {
+ /* FIXME: might want to do this eventually in the same transaction... */
+ struct TALER_KycCompletedEventP rep = {
+ .header.size = htons (sizeof (rep)),
+ .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
+ .h_payto = *h_payto
+ };
+
+ TEH_PG_event_notify (pg,
+ &rep.header,
+ NULL,
+ 0);
+ }
+ return qs;
+}
diff --git a/src/exchangedb/pg_update_kyc_attributes.h b/src/exchangedb/pg_insert_kyc_failure.h
index 5d17eb7fa..46d08df9c 100644
--- a/src/exchangedb/pg_update_kyc_attributes.h
+++ b/src/exchangedb/pg_insert_kyc_failure.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2024 Taler Systems SA
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
@@ -14,12 +14,12 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_update_kyc_attributes.h
- * @brief implementation of the update_kyc_attributes function for Postgres
+ * @file exchangedb/pg_insert_kyc_failure.h
+ * @brief implementation of the insert_kyc_failure function for Postgres
* @author Christian Grothoff
*/
-#ifndef PG_UPDATE_KYC_ATTRIBUTES_H
-#define PG_UPDATE_KYC_ATTRIBUTES_H
+#ifndef PG_INSERT_KYC_FAILURE_H
+#define PG_INSERT_KYC_FAILURE_H
#include "taler_util.h"
#include "taler_json_lib.h"
@@ -27,31 +27,24 @@
/**
- * Update KYC attribute data.
+ * Update KYC process status to finished (and failed).
*
* @param cls closure
+ * @param process_row KYC process row to update
* @param h_payto account for which the attribute data is stored
- * @param kyc_prox key for similarity search
* @param provider_section provider that must be checked
- * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
- * digits can be 0 if exact day, month or year are unknown
- * @param collection_time when was the data collected
- * @param expiration_time when does the data expire
- * @param enc_attributes_size number of bytes in @a enc_attributes
- * @param enc_attributes encrypted attribute data
+ * @param provider_account_id provider account ID
+ * @param provider_legitimization_id provider legitimization ID
* @return database transaction status
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_update_kyc_attributes (
+TEH_PG_insert_kyc_failure (
void *cls,
+ uint64_t process_row,
const struct TALER_PaytoHashP *h_payto,
- const struct GNUNET_ShortHashCode *kyc_prox,
const char *provider_section,
- const char *birthdate,
- struct GNUNET_TIME_Timestamp collection_time,
- struct GNUNET_TIME_Timestamp expiration_time,
- size_t enc_attributes_size,
- const void *enc_attributes);
+ const char *provider_account_id,
+ const char *provider_legitimization_id);
#endif
diff --git a/src/exchangedb/pg_insert_kyc_requirement_for_account.c b/src/exchangedb/pg_insert_kyc_requirement_for_account.c
index be5cbac87..95f695297 100644
--- a/src/exchangedb/pg_insert_kyc_requirement_for_account.c
+++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.c
@@ -30,11 +30,15 @@ TEH_PG_insert_kyc_requirement_for_account (
void *cls,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t *requirement_row)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
+ (NULL == reserve_pub)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_string (provider_section),
GNUNET_PQ_query_param_end
};
@@ -43,14 +47,15 @@ TEH_PG_insert_kyc_requirement_for_account (
requirement_row),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_insert_kyc_requirement_for_account() */
+ /* Used in #postgres_insert_kyc_requirement_for_account() */
PREPARE (pg,
"insert_legitimization_requirement",
"INSERT INTO legitimization_requirements"
" (h_payto"
+ " ,reserve_pub"
" ,required_checks"
" ) VALUES "
- " ($1, $2)"
+ " ($1, $2, $3)"
" ON CONFLICT (h_payto,required_checks) "
" DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */
" RETURNING legitimization_requirement_serial_id");
diff --git a/src/exchangedb/pg_insert_kyc_requirement_for_account.h b/src/exchangedb/pg_insert_kyc_requirement_for_account.h
index 5f9bf6a48..331c8ba0c 100644
--- a/src/exchangedb/pg_insert_kyc_requirement_for_account.h
+++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.h
@@ -32,6 +32,7 @@
* @param cls closure
* @param provider_section provider that must be checked
* @param h_payto account that must be KYC'ed
+ * @param reserve_pub if the account is a reserve, its public key. Maybe NULL
* @param[out] requirement_row set to legitimization requirement row for this check
* @return database transaction status
*/
@@ -40,5 +41,7 @@ TEH_PG_insert_kyc_requirement_for_account (
void *cls,
const char *provider_section,
const struct TALER_PaytoHashP *h_payto,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
uint64_t *requirement_row);
+
#endif
diff --git a/src/exchangedb/pg_insert_kyc_requirement_process.c b/src/exchangedb/pg_insert_kyc_requirement_process.c
index d520ac59c..a20db3388 100644
--- a/src/exchangedb/pg_insert_kyc_requirement_process.c
+++ b/src/exchangedb/pg_insert_kyc_requirement_process.c
@@ -24,6 +24,7 @@
#include "taler_pq_lib.h"
#include "pg_insert_kyc_requirement_process.h"
#include "pg_helper.h"
+#include <gnunet/gnunet_pq_lib.h>
enum GNUNET_DB_QueryStatus
TEH_PG_insert_kyc_requirement_process (
@@ -35,8 +36,11 @@ TEH_PG_insert_kyc_requirement_process (
uint64_t *process_row)
{
struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now
+ = GNUNET_TIME_absolute_get ();
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_absolute_time (&now),
GNUNET_PQ_query_param_string (provider_section),
(NULL != provider_account_id)
? GNUNET_PQ_query_param_string (provider_account_id)
@@ -52,20 +56,16 @@ TEH_PG_insert_kyc_requirement_process (
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_insert_kyc_requirement_process() */
PREPARE (pg,
"insert_legitimization_process",
"INSERT INTO legitimization_processes"
" (h_payto"
+ " ,start_time"
" ,provider_section"
" ,provider_user_id"
" ,provider_legitimization_id"
" ) VALUES "
- " ($1, $2, $3, $4)"
- " ON CONFLICT (h_payto,provider_section) "
- " DO UPDATE SET"
- " provider_user_id=$3"
- " ,provider_legitimization_id=$4"
+ " ($1, $2, $3, $4, $5)"
" RETURNING legitimization_process_serial_id");
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
diff --git a/src/exchangedb/pg_insert_kyc_requirement_process.h b/src/exchangedb/pg_insert_kyc_requirement_process.h
index 3f354472e..df21db8cd 100644
--- a/src/exchangedb/pg_insert_kyc_requirement_process.h
+++ b/src/exchangedb/pg_insert_kyc_requirement_process.h
@@ -45,4 +45,5 @@ TEH_PG_insert_kyc_requirement_process (
const char *provider_account_id,
const char *provider_legitimization_id,
uint64_t *process_row);
+
#endif
diff --git a/src/exchangedb/pg_insert_partner.c b/src/exchangedb/pg_insert_partner.c
index 5abb2c910..d1d6069de 100644
--- a/src/exchangedb/pg_insert_partner.c
+++ b/src/exchangedb/pg_insert_partner.c
@@ -42,7 +42,8 @@ TEH_PG_insert_partner (void *cls,
GNUNET_PQ_query_param_timestamp (&start_date),
GNUNET_PQ_query_param_timestamp (&end_date),
GNUNET_PQ_query_param_relative_time (&wad_frequency),
- TALER_PQ_query_param_amount (wad_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ wad_fee),
GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_string (partner_base_url),
GNUNET_PQ_query_param_end
@@ -56,12 +57,11 @@ TEH_PG_insert_partner (void *cls,
" ,start_date"
" ,end_date"
" ,wad_frequency"
- " ,wad_fee_val"
- " ,wad_fee_frac"
+ " ,wad_fee"
" ,master_sig"
" ,partner_base_url"
" ) VALUES "
- " ($1, $2, $3, $4, $5, $6, $7, $8)"
+ " ($1, $2, $3, $4, $5, $6, $7)"
" ON CONFLICT DO NOTHING;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_partner",
diff --git a/src/exchangedb/pg_insert_partner.h b/src/exchangedb/pg_insert_partner.h
index eed40a80e..3ebae786c 100644
--- a/src/exchangedb/pg_insert_partner.h
+++ b/src/exchangedb/pg_insert_partner.h
@@ -40,12 +40,12 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_partner (void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- struct GNUNET_TIME_Relative wad_frequency,
- const struct TALER_Amount *wad_fee,
- const char *partner_base_url,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ struct GNUNET_TIME_Relative wad_frequency,
+ const struct TALER_Amount *wad_fee,
+ const char *partner_base_url,
const struct TALER_MasterSignatureP *master_sig);
#endif
diff --git a/src/exchangedb/pg_insert_purse_request.c b/src/exchangedb/pg_insert_purse_request.c
index f42129ec4..d8d68abe8 100644
--- a/src/exchangedb/pg_insert_purse_request.c
+++ b/src/exchangedb/pg_insert_purse_request.c
@@ -56,8 +56,10 @@ TEH_PG_insert_purse_request (
GNUNET_PQ_query_param_uint32 (&age_limit),
GNUNET_PQ_query_param_uint32 (&flags32),
GNUNET_PQ_query_param_bool (in_reserve_quota),
- TALER_PQ_query_param_amount (amount),
- TALER_PQ_query_param_amount (purse_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ purse_fee),
GNUNET_PQ_query_param_auto_from_type (purse_sig),
GNUNET_PQ_query_param_end
};
@@ -74,13 +76,11 @@ TEH_PG_insert_purse_request (
" ,age_limit"
" ,flags"
" ,in_reserve_quota"
- " ,amount_with_fee_val"
- " ,amount_with_fee_frac"
- " ,purse_fee_val"
- " ,purse_fee_frac"
+ " ,amount_with_fee"
+ " ,purse_fee"
" ,purse_sig"
" ) VALUES "
- " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"
+ " ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"
" ON CONFLICT DO NOTHING;");
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_purse_request",
diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c
index d6630797a..6ecec5bcf 100644
--- a/src/exchangedb/pg_insert_records_by_table.c
+++ b/src/exchangedb/pg_insert_records_by_table.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2020, 2021, 2022 Taler Systems SA
+ Copyright (C) 2020-2023 Taler Systems SA
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -19,8 +19,9 @@
*/
/**
* @file exchangedb/pg_insert_records_by_table.c
- * @brief insert_records_by_table implementation
+ * @brief replicate_records_by_table implementation
* @author Christian Grothoff
+ * @author Özgür Kesim
*/
#include "platform.h"
#include "taler_error_codes.h"
@@ -28,6 +29,7 @@
#include "taler_pq_lib.h"
#include "pg_insert_records_by_table.h"
#include "pg_helper.h"
+#include <gnunet/gnunet_pq_lib.h>
/**
@@ -72,14 +74,20 @@ irbt_cb_table_denominations (struct PostgresClosure *pg,
&td->details.denominations.expire_deposit),
GNUNET_PQ_query_param_timestamp (
&td->details.denominations.expire_legal),
- TALER_PQ_query_param_amount (&td->details.denominations.coin),
TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.denominations.coin),
+ TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.denominations.fees.withdraw),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.denominations.fees.deposit),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.denominations.fees.refresh),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.denominations.fees.refund),
GNUNET_PQ_query_param_end
};
@@ -97,19 +105,14 @@ irbt_cb_table_denominations (struct PostgresClosure *pg,
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val"
- ",coin_frac"
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin"
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17, $18, $19, $20);");
+ " $11, $12, $13, $14, $15);");
TALER_denom_pub_hash (
&td->details.denominations.denom_pub,
@@ -227,7 +230,7 @@ irbt_cb_table_legitimization_processes (struct PostgresClosure *pg,
",provider_user_id"
",provider_legitimization_id"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
+ "($1, $3, $4, $5, $6, %7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_legitimization_processes",
params);
@@ -249,6 +252,10 @@ irbt_cb_table_legitimization_requirements (struct PostgresClosure *pg,
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (
&td->details.legitimization_requirements.h_payto),
+ td->details.legitimization_requirements.no_reserve_pub
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (
+ &td->details.legitimization_requirements.reserve_pub),
GNUNET_PQ_query_param_string (
td->details.legitimization_requirements.required_checks),
GNUNET_PQ_query_param_end
@@ -259,6 +266,7 @@ irbt_cb_table_legitimization_requirements (struct PostgresClosure *pg,
"INSERT INTO legitimization_requirements"
"(legitimization_requirement_serial_id"
",h_payto"
+ ",reserve_pub"
",required_checks"
") VALUES "
"($1, $2, $3);");
@@ -314,7 +322,9 @@ irbt_cb_table_reserves_in (struct PostgresClosure *pg,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_uint64 (&td->details.reserves_in.wire_reference),
- TALER_PQ_query_param_amount (&td->details.reserves_in.credit),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.reserves_in.credit),
GNUNET_PQ_query_param_auto_from_type (
&td->details.reserves_in.sender_account_h_payto),
GNUNET_PQ_query_param_string (
@@ -330,14 +340,13 @@ irbt_cb_table_reserves_in (struct PostgresClosure *pg,
"INSERT INTO reserves_in"
"(reserve_in_serial_id"
",wire_reference"
- ",credit_val"
- ",credit_frac"
+ ",credit"
",wire_source_h_payto"
",exchange_account_section"
",execution_date"
",reserve_pub"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_reserves_in",
params);
@@ -362,6 +371,7 @@ irbt_cb_table_reserves_open_requests (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (
&td->details.reserves_open_requests.reserve_sig),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.reserves_open_requests.reserve_payment),
GNUNET_PQ_query_param_uint32 (
&td->details.reserves_open_requests.requested_purse_limit),
@@ -376,11 +386,10 @@ irbt_cb_table_reserves_open_requests (struct PostgresClosure *pg,
",request_timestamp"
",expiration_date"
",reserve_sig"
- ",reserve_payment_val"
- ",reserve_payment_frac"
+ ",reserve_payment"
",requested_purse_limit"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_reserves_open_requests",
params);
@@ -407,6 +416,7 @@ irbt_cb_table_reserves_open_deposits (
GNUNET_PQ_query_param_auto_from_type (
&td->details.reserves_open_deposits.reserve_sig),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.reserves_open_deposits.contribution),
GNUNET_PQ_query_param_end
};
@@ -419,10 +429,9 @@ irbt_cb_table_reserves_open_deposits (
",reserve_pub"
",coin_pub"
",coin_sig"
- ",contribution_val"
- ",contribution_frac"
+ ",contribution"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_reserves_open_deposits",
params);
@@ -447,8 +456,12 @@ irbt_cb_table_reserves_close (struct PostgresClosure *pg,
&td->details.reserves_close.wtid),
GNUNET_PQ_query_param_auto_from_type (
&td->details.reserves_close.sender_account_h_payto),
- TALER_PQ_query_param_amount (&td->details.reserves_close.amount),
- TALER_PQ_query_param_amount (&td->details.reserves_close.closing_fee),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.reserves_close.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.reserves_close.closing_fee),
GNUNET_PQ_query_param_auto_from_type (
&td->details.reserves_close.reserve_pub),
GNUNET_PQ_query_param_end
@@ -461,13 +474,11 @@ irbt_cb_table_reserves_close (struct PostgresClosure *pg,
",execution_date"
",wtid"
",wire_target_h_payto"
- ",amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",amount"
+ ",closing_fee"
",reserve_pub"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_reserves_close",
params);
@@ -499,6 +510,7 @@ irbt_cb_table_reserves_out (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.reserves_out.execution_date),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.reserves_out.amount_with_fee),
GNUNET_PQ_query_param_end
};
@@ -513,10 +525,9 @@ irbt_cb_table_reserves_out (struct PostgresClosure *pg,
",reserve_uuid"
",reserve_sig"
",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7, $8);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_reserves_out",
params);
@@ -721,6 +732,7 @@ irbt_cb_table_refresh_commitments (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (
&td->details.refresh_commitments.old_coin_sig),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.refresh_commitments.amount_with_fee),
GNUNET_PQ_query_param_uint32 (
&td->details.refresh_commitments.noreveal_index),
@@ -735,12 +747,11 @@ irbt_cb_table_refresh_commitments (struct PostgresClosure *pg,
"(melt_serial_id"
",rc"
",old_coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",old_coin_pub"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_refresh_commitments",
params);
@@ -844,67 +855,106 @@ irbt_cb_table_refresh_transfer_keys (
/**
- * Function called with deposits records to insert into table.
+ * Function called with batch deposits records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
-irbt_cb_table_deposits (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_TableData *td)
+irbt_cb_table_batch_deposits (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
- GNUNET_PQ_query_param_uint64 (&td->details.deposits.shard),
- GNUNET_PQ_query_param_uint64 (&td->details.deposits.known_coin_id),
+ GNUNET_PQ_query_param_uint64 (&td->details.batch_deposits.shard),
GNUNET_PQ_query_param_auto_from_type (
- &td->details.deposits.coin_pub),
- TALER_PQ_query_param_amount (&td->details.deposits.amount_with_fee),
- GNUNET_PQ_query_param_timestamp (&td->details.deposits.wallet_timestamp),
+ &td->details.batch_deposits.merchant_pub),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.batch_deposits.wallet_timestamp),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.batch_deposits.exchange_timestamp),
GNUNET_PQ_query_param_timestamp (
- &td->details.deposits.exchange_timestamp),
- GNUNET_PQ_query_param_timestamp (&td->details.deposits.refund_deadline),
- GNUNET_PQ_query_param_timestamp (&td->details.deposits.wire_deadline),
- GNUNET_PQ_query_param_auto_from_type (&td->details.deposits.merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (
- &td->details.deposits.h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&td->details.deposits.coin_sig),
- GNUNET_PQ_query_param_auto_from_type (&td->details.deposits.wire_salt),
- GNUNET_PQ_query_param_auto_from_type (
- &td->details.deposits.wire_target_h_payto),
- GNUNET_PQ_query_param_bool (td->details.deposits.policy_blocked),
- 0 == td->details.deposits.policy_details_serial_id
+ &td->details.batch_deposits.refund_deadline),
+ GNUNET_PQ_query_param_timestamp (&td->details.batch_deposits.wire_deadline),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.batch_deposits.h_contract_terms),
+ td->details.batch_deposits.no_wallet_data_hash
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (
+ &td->details.batch_deposits.wallet_data_hash),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.batch_deposits.wire_salt),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.batch_deposits.wire_target_h_payto),
+ GNUNET_PQ_query_param_bool (td->details.batch_deposits.policy_blocked),
+ td->details.batch_deposits.no_policy_details
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_uint64 (
- &td->details.deposits.policy_details_serial_id),
+ &td->details.batch_deposits.policy_details_serial_id),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
- "insert_into_table_deposits",
- "INSERT INTO deposits"
- "(deposit_serial_id"
+ "insert_into_table_batch_deposits",
+ "INSERT INTO batch_deposits"
+ "(batch_deposit_serial_id"
",shard"
- ",known_coin_id"
- ",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",merchant_pub"
",wallet_timestamp"
",exchange_timestamp"
",refund_deadline"
",wire_deadline"
- ",merchant_pub"
",h_contract_terms"
- ",coin_sig"
+ ",wallet_data_hash"
",wire_salt"
",wire_target_h_payto"
- ",policy_blocked"
",policy_details_serial_id"
+ ",policy_blocked"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
- " $11, $12, $13, $14, $15, $16, $17);");
+ " $11, $12, $13);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_batch_deposits",
+ params);
+}
+
+
+/**
+ * Function called with deposits records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_coin_deposits (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_uint64 (
+ &td->details.coin_deposits.batch_deposit_serial_id),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.coin_deposits.coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.coin_deposits.coin_sig),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.coin_deposits.amount_with_fee),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_coin_deposits",
+ "INSERT INTO coin_deposits"
+ "(coin_deposit_serial_id"
+ ",batch_deposit_serial_id"
+ ",coin_pub"
+ ",coin_sig"
+ ",amount_with_fee"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_into_table_deposits",
+ "insert_into_table_coin_deposits",
params);
}
@@ -924,8 +974,11 @@ irbt_cb_table_refunds (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (&td->details.refunds.coin_pub),
GNUNET_PQ_query_param_auto_from_type (&td->details.refunds.merchant_sig),
GNUNET_PQ_query_param_uint64 (&td->details.refunds.rtransaction_id),
- TALER_PQ_query_param_amount (&td->details.refunds.amount_with_fee),
- GNUNET_PQ_query_param_uint64 (&td->details.refunds.deposit_serial_id),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.refunds.amount_with_fee),
+ GNUNET_PQ_query_param_uint64 (
+ &td->details.refunds.batch_deposit_serial_id),
GNUNET_PQ_query_param_end
};
@@ -936,11 +989,10 @@ irbt_cb_table_refunds (struct PostgresClosure *pg,
",coin_pub"
",merchant_sig"
",rtransaction_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_serial_id"
+ ",amount_with_fee"
+ ",batch_deposit_serial_id"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_refunds",
params);
@@ -965,7 +1017,9 @@ irbt_cb_table_wire_out (struct PostgresClosure *pg,
&td->details.wire_out.wire_target_h_payto),
GNUNET_PQ_query_param_string (
td->details.wire_out.exchange_account_section),
- TALER_PQ_query_param_amount (&td->details.wire_out.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.wire_out.amount),
GNUNET_PQ_query_param_end
};
@@ -977,10 +1031,9 @@ irbt_cb_table_wire_out (struct PostgresClosure *pg,
",wtid_raw"
",wire_target_h_payto"
",exchange_account_section"
- ",amount_val"
- ",amount_frac"
+ ",amount"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wire_out",
params);
@@ -1000,7 +1053,7 @@ irbt_cb_table_aggregation_tracking (struct PostgresClosure *pg,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_uint64 (
- &td->details.aggregation_tracking.deposit_serial_id),
+ &td->details.aggregation_tracking.batch_deposit_serial_id),
GNUNET_PQ_query_param_auto_from_type (
&td->details.aggregation_tracking.wtid_raw),
GNUNET_PQ_query_param_end
@@ -1010,7 +1063,7 @@ irbt_cb_table_aggregation_tracking (struct PostgresClosure *pg,
"insert_into_table_aggregation_tracking",
"INSERT INTO aggregation_tracking"
"(aggregation_serial_id"
- ",deposit_serial_id"
+ ",batch_deposit_serial_id"
",wtid_raw"
") VALUES "
"($1, $2, $3);");
@@ -1035,8 +1088,12 @@ irbt_cb_table_wire_fee (struct PostgresClosure *pg,
GNUNET_PQ_query_param_string (td->details.wire_fee.wire_method),
GNUNET_PQ_query_param_timestamp (&td->details.wire_fee.start_date),
GNUNET_PQ_query_param_timestamp (&td->details.wire_fee.end_date),
- TALER_PQ_query_param_amount (&td->details.wire_fee.fees.wire),
- TALER_PQ_query_param_amount (&td->details.wire_fee.fees.closing),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.wire_fee.fees.wire),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.wire_fee.fees.closing),
GNUNET_PQ_query_param_auto_from_type (&td->details.wire_fee.master_sig),
GNUNET_PQ_query_param_end
};
@@ -1048,13 +1105,11 @@ irbt_cb_table_wire_fee (struct PostgresClosure *pg,
",wire_method"
",start_date"
",end_date"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",wire_fee"
+ ",closing_fee"
",master_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wire_fee",
params);
@@ -1079,10 +1134,13 @@ irbt_cb_table_global_fee (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.global_fee.end_date),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.global_fee.fees.history),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.global_fee.fees.account),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.global_fee.fees.purse),
GNUNET_PQ_query_param_relative_time (
&td->details.global_fee.purse_timeout),
@@ -1101,18 +1159,15 @@ irbt_cb_table_global_fee (struct PostgresClosure *pg,
"(global_fee_serial"
",start_date"
",end_date"
- ",history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",history_fee"
+ ",account_fee"
+ ",purse_fee"
",purse_timeout"
",history_expiration"
",purse_account_limit"
",master_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_global_fee",
params);
@@ -1133,7 +1188,9 @@ irbt_cb_table_recoup (struct PostgresClosure *pg,
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (&td->details.recoup.coin_sig),
GNUNET_PQ_query_param_auto_from_type (&td->details.recoup.coin_blind),
- TALER_PQ_query_param_amount (&td->details.recoup.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.recoup.amount),
GNUNET_PQ_query_param_timestamp (&td->details.recoup.timestamp),
GNUNET_PQ_query_param_auto_from_type (
&td->details.recoup.coin_pub),
@@ -1147,13 +1204,12 @@ irbt_cb_table_recoup (struct PostgresClosure *pg,
"(recoup_uuid"
",coin_sig"
",coin_blind"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",recoup_timestamp"
",coin_pub"
",reserve_out_serial_id"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_recoup",
params);
@@ -1175,7 +1231,9 @@ irbt_cb_table_recoup_refresh (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (&td->details.recoup_refresh.coin_sig),
GNUNET_PQ_query_param_auto_from_type (
&td->details.recoup_refresh.coin_blind),
- TALER_PQ_query_param_amount (&td->details.recoup_refresh.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.recoup_refresh.amount),
GNUNET_PQ_query_param_timestamp (&td->details.recoup_refresh.timestamp),
GNUNET_PQ_query_param_uint64 (&td->details.recoup_refresh.known_coin_id),
GNUNET_PQ_query_param_auto_from_type (
@@ -1190,14 +1248,13 @@ irbt_cb_table_recoup_refresh (struct PostgresClosure *pg,
"(recoup_refresh_uuid"
",coin_sig"
",coin_blind"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",recoup_timestamp"
",known_coin_id"
",coin_pub"
",rrc_serial"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7, $8);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_recoup_refresh",
params);
@@ -1254,10 +1311,17 @@ irbt_cb_table_policy_details (struct PostgresClosure *pg,
(td->details.policy_details.no_policy_json)
? GNUNET_PQ_query_param_null ()
: TALER_PQ_query_param_json (td->details.policy_details.policy_json),
- TALER_PQ_query_param_amount (&td->details.policy_details.commitment),
- TALER_PQ_query_param_amount (&td->details.policy_details.accumulated_total),
- TALER_PQ_query_param_amount (&td->details.policy_details.fee),
- TALER_PQ_query_param_amount (&td->details.policy_details.transferable),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.policy_details.commitment),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.policy_details.accumulated_total),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.policy_details.fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &td->details.policy_details.transferable),
GNUNET_PQ_query_param_timestamp (&td->details.policy_details.deadline),
GNUNET_PQ_query_param_uint16 (
&td->details.policy_details.fulfillment_state),
@@ -1275,18 +1339,14 @@ irbt_cb_table_policy_details (struct PostgresClosure *pg,
",policy_hash_code"
",policy_json"
",deadline"
- ",commitment_val"
- ",commitment_frac"
- ",accumulated_total_val"
- ",accumulated_total_frac"
- ",fee_val"
- ",fee_frac"
- ",transferable_val"
- ",transferable_frac"
+ ",commitment"
+ ",accumulated_total"
+ ",fee"
+ ",transferable"
",fulfillment_state"
",fulfillment_id"
") VALUES "
- "($1, $2);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_policy_details",
params);
@@ -1359,8 +1419,12 @@ irbt_cb_table_purse_requests (struct PostgresClosure *pg,
&td->details.purse_requests.h_contract_terms),
GNUNET_PQ_query_param_uint32 (&td->details.purse_requests.age_limit),
GNUNET_PQ_query_param_uint32 (&td->details.purse_requests.flags),
- TALER_PQ_query_param_amount (&td->details.purse_requests.amount_with_fee),
- TALER_PQ_query_param_amount (&td->details.purse_requests.purse_fee),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.purse_requests.amount_with_fee),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.purse_requests.purse_fee),
GNUNET_PQ_query_param_auto_from_type (
&td->details.purse_requests.purse_sig),
GNUNET_PQ_query_param_end
@@ -1377,13 +1441,11 @@ irbt_cb_table_purse_requests (struct PostgresClosure *pg,
",h_contract_terms"
",age_limit"
",flags"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",amount_with_fee"
+ ",purse_fee"
",purse_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_purse_requests",
params);
@@ -1407,7 +1469,7 @@ irbt_cb_table_purse_decision (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.purse_decision.action_timestamp),
GNUNET_PQ_query_param_bool (
- &td->details.purse_decision.refunded),
+ td->details.purse_decision.refunded),
GNUNET_PQ_query_param_end
};
@@ -1481,7 +1543,9 @@ irbt_cb_table_purse_deposits (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (
&td->details.purse_deposits.purse_pub),
GNUNET_PQ_query_param_auto_from_type (&td->details.purse_deposits.coin_pub),
- TALER_PQ_query_param_amount (&td->details.purse_deposits.amount_with_fee),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.purse_deposits.amount_with_fee),
GNUNET_PQ_query_param_auto_from_type (&td->details.purse_deposits.coin_sig),
GNUNET_PQ_query_param_end
};
@@ -1493,11 +1557,10 @@ irbt_cb_table_purse_deposits (struct PostgresClosure *pg,
",partner_serial_id"
",purse_pub"
",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",coin_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_purse_deposits",
params);
@@ -1562,6 +1625,7 @@ irbt_cb_table_history_requests (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (
&td->details.history_requests.reserve_sig),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.history_requests.history_fee),
GNUNET_PQ_query_param_end
};
@@ -1573,10 +1637,9 @@ irbt_cb_table_history_requests (struct PostgresClosure *pg,
",reserve_pub"
",request_timestamp"
",reserve_sig"
- ",history_fee_val"
- ",history_fee_frac"
+ ",history_fee"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
+ "($1, $2, $3, $4, $5);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_history_requests",
params);
@@ -1602,8 +1665,10 @@ irbt_cb_table_close_requests (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (
&td->details.close_requests.reserve_sig),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.close_requests.close),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.close_requests.close_fee),
GNUNET_PQ_query_param_string (
td->details.close_requests.payto_uri),
@@ -1617,13 +1682,11 @@ irbt_cb_table_close_requests (struct PostgresClosure *pg,
",reserve_pub"
",close_timestamp"
",reserve_sig"
- ",close_val"
- ",close_frac"
- ",close_fee_val"
- ",close_fee_frac"
+ ",close"
+ ",close_fee"
",payto_uri"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_close_requests",
params);
@@ -1644,7 +1707,9 @@ irbt_cb_table_wads_out (struct PostgresClosure *pg,
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (&td->details.wads_out.wad_id),
GNUNET_PQ_query_param_uint64 (&td->details.wads_out.partner_serial_id),
- TALER_PQ_query_param_amount (&td->details.wads_out.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.wads_out.amount),
GNUNET_PQ_query_param_timestamp (&td->details.wads_out.execution_time),
GNUNET_PQ_query_param_end
};
@@ -1655,11 +1720,10 @@ irbt_cb_table_wads_out (struct PostgresClosure *pg,
"(wad_out_serial_id"
",wad_id"
",partner_serial_id"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",execution_time"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
+ "($1, $2, $3, $4, $5);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wads_out",
params);
@@ -1691,10 +1755,13 @@ irbt_cb_table_wads_out_entries (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.wads_out_entries.merge_timestamp),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_out_entries.amount_with_fee),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_out_entries.wad_fee),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_out_entries.deposit_fees),
GNUNET_PQ_query_param_auto_from_type (
&td->details.wads_out_entries.reserve_sig),
@@ -1713,16 +1780,13 @@ irbt_cb_table_wads_out_entries (struct PostgresClosure *pg,
",h_contract"
",purse_expiration"
",merge_timestamp"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wad_fee_val"
- ",wad_fee_frac"
- ",deposit_fees_val"
- ",deposit_fees_frac"
+ ",amount_with_fee"
+ ",wad_fee"
+ ",deposit_fees"
",reserve_sig"
",purse_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wads_out_entries",
params);
@@ -1743,7 +1807,9 @@ irbt_cb_table_wads_in (struct PostgresClosure *pg,
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_auto_from_type (&td->details.wads_in.wad_id),
GNUNET_PQ_query_param_string (td->details.wads_in.origin_exchange_url),
- TALER_PQ_query_param_amount (&td->details.wads_in.amount),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.wads_in.amount),
GNUNET_PQ_query_param_timestamp (&td->details.wads_in.arrival_time),
GNUNET_PQ_query_param_end
};
@@ -1754,11 +1820,10 @@ irbt_cb_table_wads_in (struct PostgresClosure *pg,
"(wad_in_serial_id"
",wad_id"
",origin_exchange_url"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",arrival_time"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
+ "($1, $2, $3, $4, $5);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wads_in",
params);
@@ -1788,10 +1853,13 @@ irbt_cb_table_wads_in_entries (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.wads_in_entries.merge_timestamp),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_in_entries.amount_with_fee),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_in_entries.wad_fee),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.wads_in_entries.deposit_fees),
GNUNET_PQ_query_param_auto_from_type (
&td->details.wads_in_entries.reserve_sig),
@@ -1810,16 +1878,13 @@ irbt_cb_table_wads_in_entries (struct PostgresClosure *pg,
",h_contract"
",purse_expiration"
",merge_timestamp"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wad_fee_val"
- ",wad_fee_frac"
- ",deposit_fees_val"
- ",deposit_fees_frac"
+ ",amount_with_fee"
+ ",wad_fee"
+ ",deposit_fees"
",reserve_sig"
",purse_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_wads_in_entries",
params);
@@ -1847,6 +1912,7 @@ irbt_cb_table_profit_drains (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp (
&td->details.profit_drains.trigger_date),
TALER_PQ_query_param_amount (
+ pg->conn,
&td->details.profit_drains.amount),
GNUNET_PQ_query_param_auto_from_type (
&td->details.profit_drains.master_sig),
@@ -1861,23 +1927,252 @@ irbt_cb_table_profit_drains (struct PostgresClosure *pg,
",account_section"
",payto_uri"
",trigger_date"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",master_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);");
+ "($1, $2, $3, $4, $5, $6, $7);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_into_table_profit_drains",
params);
}
+/**
+ * Function called with aml_staff records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_aml_staff (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.aml_staff.decider_pub),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.aml_staff.master_sig),
+ GNUNET_PQ_query_param_string (
+ td->details.aml_staff.decider_name),
+ GNUNET_PQ_query_param_bool (
+ td->details.aml_staff.is_active),
+ GNUNET_PQ_query_param_bool (
+ td->details.aml_staff.read_only),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.aml_staff.last_change),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_aml_staff",
+ "INSERT INTO aml_staff"
+ "(aml_staff_uuid"
+ ",decider_pub"
+ ",master_sig"
+ ",decider_name"
+ ",is_active"
+ ",read_only"
+ ",last_change"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_aml_staff",
+ params);
+}
+
+
+/**
+ * Function called with aml_history records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_aml_history (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ uint32_t status32 = td->details.aml_history.new_status;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.aml_history.h_payto),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.aml_history.new_threshold),
+ GNUNET_PQ_query_param_uint32 (
+ &status32),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.aml_history.decision_time),
+ GNUNET_PQ_query_param_string (
+ td->details.aml_history.justification),
+ (NULL == td->details.aml_history.kyc_requirements)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (
+ td->details.aml_history.kyc_requirements),
+ GNUNET_PQ_query_param_uint64 (
+ &td->details.aml_history.kyc_req_row),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.aml_history.decider_pub),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.aml_history.decider_sig),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_aml_history",
+ "INSERT INTO aml_history"
+ "(aml_history_serial_id"
+ ",h_payto"
+ ",new_threshold"
+ ",new_status"
+ ",decision_time"
+ ",justification"
+ ",kyc_requirements"
+ ",kyc_req_row"
+ ",decider_pub"
+ ",decider_sig"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_aml_history",
+ params);
+}
+
+
+/**
+ * Function called with kyc_attributes records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_kyc_attributes (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.kyc_attributes.h_payto),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.kyc_attributes.kyc_prox),
+ GNUNET_PQ_query_param_string (
+ td->details.kyc_attributes.provider),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.kyc_attributes.collection_time),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.kyc_attributes.expiration_time),
+ GNUNET_PQ_query_param_fixed_size (
+ &td->details.kyc_attributes.encrypted_attributes,
+ td->details.kyc_attributes.encrypted_attributes_size),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_kyc_attributes",
+ "INSERT INTO kyc_attributes"
+ "(kyc_attributes_serial_id"
+ ",h_payto"
+ ",kyc_prox"
+ ",provider"
+ ",collection_time"
+ ",expiration_time"
+ ",encrypted_attributes"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_kyc_attributes",
+ params);
+}
+
+
+/**
+ * Function called with purse_deletion records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_purse_deletion (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.purse_deletion.purse_pub),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.purse_deletion.purse_sig),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_purse_deletion",
+ "INSERT INTO purse_deletion"
+ "(purse_deletion_serial_id"
+ ",purse_pub"
+ ",purse_sig"
+ ") VALUES "
+ "($1, $2, $3);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_purse_deletion",
+ params);
+}
+
+
+/**
+ * Function called with age_withdraw records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_age_withdraw (struct PostgresClosure *pg,
+ const struct
+ TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.age_withdraw.h_commitment),
+ TALER_PQ_query_param_amount (
+ pg->conn,
+ &td->details.age_withdraw.amount_with_fee),
+ GNUNET_PQ_query_param_uint16 (
+ &td->details.age_withdraw.max_age),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.age_withdraw.reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.age_withdraw.reserve_sig),
+ GNUNET_PQ_query_param_uint32 (
+ &td->details.age_withdraw.noreveal_index),
+ /* TODO: other fields, too! */
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_age_withdraw",
+ "INSERT INTO age_withdraw"
+ "(age_withdraw_commitment_id"
+ ",h_commitment"
+ ",amount_with_fee"
+ ",max_age"
+ ",reserve_pub"
+ ",reserve_sig"
+ ",noreveal_index"
+ ") VALUES "
+ "($1, $2, $3, $4, $5, $6, $7, $8);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_age_withdraw",
+ params);
+}
+
+
enum GNUNET_DB_QueryStatus
TEH_PG_insert_records_by_table (void *cls,
const struct TALER_EXCHANGEDB_TableData *td)
{
struct PostgresClosure *pg = cls;
- InsertRecordCallback rh;
+ InsertRecordCallback rh = NULL;
switch (td->table)
{
@@ -1938,8 +2233,11 @@ TEH_PG_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS:
rh = &irbt_cb_table_refresh_transfer_keys;
break;
- case TALER_EXCHANGEDB_RT_DEPOSITS:
- rh = &irbt_cb_table_deposits;
+ case TALER_EXCHANGEDB_RT_BATCH_DEPOSITS:
+ rh = &irbt_cb_table_batch_deposits;
+ break;
+ case TALER_EXCHANGEDB_RT_COIN_DEPOSITS:
+ rh = &irbt_cb_table_coin_deposits;
break;
case TALER_EXCHANGEDB_RT_REFUNDS:
rh = &irbt_cb_table_refunds;
@@ -2007,7 +2305,24 @@ TEH_PG_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_PROFIT_DRAINS:
rh = &irbt_cb_table_profit_drains;
break;
- default:
+ case TALER_EXCHANGEDB_RT_AML_STAFF:
+ rh = &irbt_cb_table_aml_staff;
+ break;
+ case TALER_EXCHANGEDB_RT_AML_HISTORY:
+ rh = &irbt_cb_table_aml_history;
+ break;
+ case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
+ rh = &irbt_cb_table_kyc_attributes;
+ break;
+ case TALER_EXCHANGEDB_RT_PURSE_DELETION:
+ rh = &irbt_cb_table_purse_deletion;
+ break;
+ case TALER_EXCHANGEDB_RT_AGE_WITHDRAW:
+ rh = &irbt_cb_table_age_withdraw;
+ break;
+ }
+ if (NULL == rh)
+ {
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
@@ -2016,4 +2331,4 @@ TEH_PG_insert_records_by_table (void *cls,
}
-/* end of irbt_callbacks.c */
+/* end of pg_insert_records_by_table.c */
diff --git a/src/exchangedb/pg_insert_refund.c b/src/exchangedb/pg_insert_refund.c
index 047df0334..e989c91bc 100644
--- a/src/exchangedb/pg_insert_refund.c
+++ b/src/exchangedb/pg_insert_refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -28,7 +28,7 @@
enum GNUNET_DB_QueryStatus
TEH_PG_insert_refund (void *cls,
- const struct TALER_EXCHANGEDB_Refund *refund)
+ const struct TALER_EXCHANGEDB_Refund *refund)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -37,26 +37,25 @@ TEH_PG_insert_refund (void *cls,
GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig),
GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
GNUNET_PQ_query_param_uint64 (&refund->details.rtransaction_id),
- TALER_PQ_query_param_amount (&refund->details.refund_amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ &refund->details.refund_amount),
GNUNET_PQ_query_param_end
};
GNUNET_assert (GNUNET_YES ==
TALER_amount_cmp_currency (&refund->details.refund_amount,
&refund->details.refund_fee));
-
- /* Used in #postgres_insert_refund() to store refund information */
PREPARE (pg,
"insert_refund",
"INSERT INTO refunds "
- "(coin_pub "
- ",deposit_serial_id"
- ",merchant_sig "
- ",rtransaction_id "
- ",amount_with_fee_val "
- ",amount_with_fee_frac "
- ") SELECT $1, deposit_serial_id, $3, $5, $6, $7"
- " FROM deposits"
+ "(coin_pub"
+ ",batch_deposit_serial_id"
+ ",merchant_sig"
+ ",rtransaction_id"
+ ",amount_with_fee"
+ ") SELECT $1, cdep.batch_deposit_serial_id, $3, $5, $6"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep USING (batch_deposit_serial_id)"
" WHERE coin_pub=$1"
" AND h_contract_terms=$4"
" AND merchant_pub=$2");
diff --git a/src/exchangedb/pg_insert_reserve_closed.c b/src/exchangedb/pg_insert_reserve_closed.c
index d17c37edc..6644fb892 100644
--- a/src/exchangedb/pg_insert_reserve_closed.c
+++ b/src/exchangedb/pg_insert_reserve_closed.c
@@ -51,26 +51,25 @@ TEH_PG_insert_reserve_closed (
GNUNET_PQ_query_param_timestamp (&execution_date),
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
- TALER_PQ_query_param_amount (amount_with_fee),
- TALER_PQ_query_param_amount (closing_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount_with_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ closing_fee),
GNUNET_PQ_query_param_uint64 (&close_request_row),
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_insert_reserve_closed() */
PREPARE (pg,
- "reserves_close_insert",
- "INSERT INTO reserves_close "
- "(reserve_pub"
- ",execution_date"
- ",wtid"
- ",wire_target_h_payto"
- ",amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
- ",close_request_row"
- ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+ "reserves_close_insert",
+ "INSERT INTO reserves_close "
+ "(reserve_pub"
+ ",execution_date"
+ ",wtid"
+ ",wire_target_h_payto"
+ ",amount"
+ ",closing_fee"
+ ",close_request_row"
+ ") VALUES ($1, $2, $3, $4, $5, $6, $7);");
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"reserves_close_insert",
@@ -83,7 +82,7 @@ TEH_PG_insert_reserve_closed (
reserve.pub = *reserve_pub;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
(qs = TEH_PG_reserves_get (cls,
- &reserve)))
+ &reserve)))
{
/* Existence should have been checked before we got here... */
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@@ -110,5 +109,5 @@ TEH_PG_insert_reserve_closed (
GNUNET_break (TALER_AAR_RESULT_ZERO == ret);
}
return TEH_PG_reserves_update (cls,
- &reserve);
+ &reserve);
}
diff --git a/src/exchangedb/pg_insert_reserve_open_deposit.c b/src/exchangedb/pg_insert_reserve_open_deposit.c
index 8bf70e7b2..f9cedcbe7 100644
--- a/src/exchangedb/pg_insert_reserve_open_deposit.c
+++ b/src/exchangedb/pg_insert_reserve_open_deposit.c
@@ -44,7 +44,8 @@ TEH_PG_insert_reserve_open_deposit (
GNUNET_PQ_query_param_auto_from_type (coin_sig),
GNUNET_PQ_query_param_auto_from_type (reserve_sig),
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_amount (coin_total),
+ TALER_PQ_query_param_amount (pg->conn,
+ coin_total),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -58,7 +59,7 @@ TEH_PG_insert_reserve_open_deposit (
"SELECT "
" out_insufficient_funds"
" FROM exchange_do_reserve_open_deposit"
- " ($1,$2,$3,$4,$5,$6,$7);");
+ " ($1,$2,$3,$4,$5,$6);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"insert_reserve_open_deposit",
params,
diff --git a/src/exchangedb/pg_insert_wire.c b/src/exchangedb/pg_insert_wire.c
index 75323b6fc..b1364cbb3 100644
--- a/src/exchangedb/pg_insert_wire.c
+++ b/src/exchangedb/pg_insert_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023, 2024 Taler Systems SA
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
@@ -29,14 +29,28 @@
enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire (void *cls,
const char *payto_uri,
+ const char *conversion_url,
+ const json_t *debit_restrictions,
+ const json_t *credit_restrictions,
struct GNUNET_TIME_Timestamp start_date,
- const struct TALER_MasterSignatureP *master_sig)
+ const struct TALER_MasterSignatureP *master_sig,
+ const char *bank_label,
+ int64_t priority)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (payto_uri),
+ NULL == conversion_url
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (conversion_url),
+ TALER_PQ_query_param_json (debit_restrictions),
+ TALER_PQ_query_param_json (credit_restrictions),
GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_timestamp (&start_date),
+ NULL == bank_label
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (bank_label),
+ GNUNET_PQ_query_param_int64 (&priority),
GNUNET_PQ_query_param_end
};
@@ -44,11 +58,16 @@ TEH_PG_insert_wire (void *cls,
"insert_wire",
"INSERT INTO wire_accounts "
"(payto_uri"
+ ",conversion_url"
+ ",debit_restrictions"
+ ",credit_restrictions"
",master_sig"
",is_active"
",last_change"
+ ",bank_label"
+ ",priority"
") VALUES "
- "($1, $2, true, $3);");
+ "($1, $2, $3, $4, $5, true, $6, $7, $8);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_wire",
params);
diff --git a/src/exchangedb/pg_insert_wire.h b/src/exchangedb/pg_insert_wire.h
index 15ce08674..7a5e4caca 100644
--- a/src/exchangedb/pg_insert_wire.h
+++ b/src/exchangedb/pg_insert_wire.h
@@ -29,16 +29,27 @@
*
* @param cls closure
* @param payto_uri wire account of the exchange
+ * @param conversion_url URL of a conversion service, NULL if there is no conversion
+ * @param debit_restrictions JSON array with debit restrictions on the account
+ * @param credit_restrictions JSON array with credit restrictions on the account
* @param start_date date when the account was added by the offline system
* (only to be used for replay detection)
* @param master_sig public signature affirming the existence of the account,
* must be of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS
+ * @param bank_label label to show this entry under in the UI, can be NULL
+ * @param priority determines order in which entries are shown in the UI
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire (void *cls,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp start_date,
- const struct TALER_MasterSignatureP *master_sig);
+ const char *payto_uri,
+ const char *conversion_url,
+ const json_t *debit_restrictions,
+ const json_t *credit_restrictions,
+ struct GNUNET_TIME_Timestamp start_date,
+ const struct TALER_MasterSignatureP *master_sig,
+ const char *bank_label,
+ int64_t priority);
+
#endif
diff --git a/src/exchangedb/pg_insert_wire_fee.c b/src/exchangedb/pg_insert_wire_fee.c
index 278ec2bcb..af818bcca 100644
--- a/src/exchangedb/pg_insert_wire_fee.c
+++ b/src/exchangedb/pg_insert_wire_fee.c
@@ -26,21 +26,24 @@
#include "pg_helper.h"
#include "pg_get_wire_fee.h"
+
enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire_fee (void *cls,
- const char *type,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_WireFeeSet *fees,
- const struct TALER_MasterSignatureP *master_sig)
+ const char *type,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_WireFeeSet *fees,
+ const struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (type),
GNUNET_PQ_query_param_timestamp (&start_date),
GNUNET_PQ_query_param_timestamp (&end_date),
- TALER_PQ_query_param_amount (&fees->wire),
- TALER_PQ_query_param_amount (&fees->closing),
+ TALER_PQ_query_param_amount (pg->conn,
+ &fees->wire),
+ TALER_PQ_query_param_amount (pg->conn,
+ &fees->closing),
GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_end
};
@@ -51,12 +54,12 @@ TEH_PG_insert_wire_fee (void *cls,
enum GNUNET_DB_QueryStatus qs;
qs = TEH_PG_get_wire_fee (pg,
- type,
- start_date,
- &sd,
- &ed,
- &wx,
- &sig);
+ type,
+ start_date,
+ &sd,
+ &ed,
+ &wx,
+ &sig);
if (qs < 0)
return qs;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
@@ -88,20 +91,17 @@ TEH_PG_insert_wire_fee (void *cls,
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
- /* Used in #postgres_insert_wire_fee */
PREPARE (pg,
"insert_wire_fee",
"INSERT INTO wire_fee "
"(wire_method"
",start_date"
",end_date"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",wire_fee"
+ ",closing_fee"
",master_sig"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);");
+ "($1, $2, $3, $4, $5, $6);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_wire_fee",
params);
diff --git a/src/exchangedb/pg_insert_wire_fee.h b/src/exchangedb/pg_insert_wire_fee.h
index e53faf5a5..15c1a39f8 100644
--- a/src/exchangedb/pg_insert_wire_fee.h
+++ b/src/exchangedb/pg_insert_wire_fee.h
@@ -38,9 +38,9 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_insert_wire_fee (void *cls,
- const char *type,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_WireFeeSet *fees,
+ const char *type,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_WireFeeSet *fees,
const struct TALER_MasterSignatureP *master_sig);
#endif
diff --git a/src/exchangedb/pg_iterate_active_auditors.h b/src/exchangedb/pg_iterate_active_auditors.h
index 1247d2d3d..f0e2808e9 100644
--- a/src/exchangedb/pg_iterate_active_auditors.h
+++ b/src/exchangedb/pg_iterate_active_auditors.h
@@ -36,6 +36,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_iterate_active_auditors (void *cls,
- TALER_EXCHANGEDB_AuditorsCallback cb,
+ TALER_EXCHANGEDB_AuditorsCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_iterate_active_signkeys.h b/src/exchangedb/pg_iterate_active_signkeys.h
index b99dfa8df..5ebba9f5a 100644
--- a/src/exchangedb/pg_iterate_active_signkeys.h
+++ b/src/exchangedb/pg_iterate_active_signkeys.h
@@ -37,7 +37,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_iterate_active_signkeys (void *cls,
- TALER_EXCHANGEDB_ActiveSignkeysCallback cb,
+ TALER_EXCHANGEDB_ActiveSignkeysCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_iterate_auditor_denominations.h b/src/exchangedb/pg_iterate_auditor_denominations.h
index da1f36701..1278e8a9f 100644
--- a/src/exchangedb/pg_iterate_auditor_denominations.h
+++ b/src/exchangedb/pg_iterate_auditor_denominations.h
@@ -41,4 +41,5 @@ TEH_PG_iterate_auditor_denominations (
void *cls,
TALER_EXCHANGEDB_AuditorDenominationsCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_iterate_denomination_info.c b/src/exchangedb/pg_iterate_denomination_info.c
index ba7026ebc..cab51d5ce 100644
--- a/src/exchangedb/pg_iterate_denomination_info.c
+++ b/src/exchangedb/pg_iterate_denomination_info.c
@@ -155,7 +155,6 @@ TEH_PG_iterate_denomination_info (void *cls,
.pg = pg
};
- /* Used in #postgres_iterate_denomination_info() */
PREPARE (pg,
"denomination_iterate",
"SELECT"
@@ -165,16 +164,11 @@ TEH_PG_iterate_denomination_info (void *cls,
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin" /* value of this denom */
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",denom_pub"
",age_mask"
" FROM denominations;");
diff --git a/src/exchangedb/pg_iterate_denomination_info.h b/src/exchangedb/pg_iterate_denomination_info.h
index 57847a515..27c08d0a9 100644
--- a/src/exchangedb/pg_iterate_denomination_info.h
+++ b/src/exchangedb/pg_iterate_denomination_info.h
@@ -35,7 +35,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_iterate_denomination_info (void *cls,
- TALER_EXCHANGEDB_DenominationCallback cb,
+ TALER_EXCHANGEDB_DenominationCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_iterate_denominations.c b/src/exchangedb/pg_iterate_denominations.c
index a38257689..684aa165a 100644
--- a/src/exchangedb/pg_iterate_denominations.c
+++ b/src/exchangedb/pg_iterate_denominations.c
@@ -72,6 +72,8 @@ dominations_cb_helper (void *cls,
struct TALER_DenominationHashP h_denom_pub = {0};
bool revoked;
struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("denominations_serial",
+ &meta.serial),
GNUNET_PQ_result_spec_auto_from_type ("master_sig",
&master_sig),
GNUNET_PQ_result_spec_bool ("revoked",
@@ -141,34 +143,27 @@ TEH_PG_iterate_denominations (void *cls,
.pg = pg
};
- /* Used in #postgres_iterate_denominations() */
PREPARE (pg,
"select_denominations",
"SELECT"
- " denominations.master_sig"
+ " denominations_serial"
+ ",denominations.master_sig"
",denom_revocations_serial_id IS NOT NULL AS revoked"
",valid_from"
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val" /* value of this denom */
- ",coin_frac" /* fractional value of this denom */
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin" /* value of this denom */
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",denom_type"
",age_mask"
",denom_pub"
" FROM denominations"
" LEFT JOIN "
" denomination_revocations USING (denominations_serial);");
-
-
return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"select_denominations",
params,
diff --git a/src/exchangedb/pg_iterate_denominations.h b/src/exchangedb/pg_iterate_denominations.h
index a205fc6ba..9f59fc803 100644
--- a/src/exchangedb/pg_iterate_denominations.h
+++ b/src/exchangedb/pg_iterate_denominations.h
@@ -38,7 +38,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_iterate_denominations (void *cls,
- TALER_EXCHANGEDB_DenominationsCallback cb,
+ TALER_EXCHANGEDB_DenominationsCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_iterate_reserve_close_info.c b/src/exchangedb/pg_iterate_reserve_close_info.c
index f1b2d452b..ff0a813c3 100644
--- a/src/exchangedb/pg_iterate_reserve_close_info.c
+++ b/src/exchangedb/pg_iterate_reserve_close_info.c
@@ -113,8 +113,7 @@ TEH_PG_iterate_reserve_close_info (
PREPARE (pg,
"iterate_reserve_close_info",
"SELECT"
- " amount_val"
- ",amount_frac"
+ " amount"
",execution_date"
" FROM reserves_close"
" WHERE wire_target_h_payto=$1"
diff --git a/src/exchangedb/pg_kyc_provider_account_lookup.c b/src/exchangedb/pg_kyc_provider_account_lookup.c
index 32cd65f7d..f9db2cbc1 100644
--- a/src/exchangedb/pg_kyc_provider_account_lookup.c
+++ b/src/exchangedb/pg_kyc_provider_account_lookup.c
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
enum GNUNET_DB_QueryStatus
TEH_PG_kyc_provider_account_lookup (
void *cls,
@@ -37,8 +36,8 @@ TEH_PG_kyc_provider_account_lookup (
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (provider_section),
GNUNET_PQ_query_param_string (provider_legitimization_id),
+ GNUNET_PQ_query_param_string (provider_section),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -48,7 +47,7 @@ TEH_PG_kyc_provider_account_lookup (
process_row),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_kyc_provider_account_lookup() */
+
PREPARE (pg,
"get_wire_target_by_legitimization_id",
"SELECT "
diff --git a/src/exchangedb/pg_kyc_provider_account_lookup.h b/src/exchangedb/pg_kyc_provider_account_lookup.h
index 41bcb86ae..74f90d88d 100644
--- a/src/exchangedb/pg_kyc_provider_account_lookup.h
+++ b/src/exchangedb/pg_kyc_provider_account_lookup.h
@@ -44,4 +44,5 @@ TEH_PG_kyc_provider_account_lookup (
const char *provider_legitimization_id,
struct TALER_PaytoHashP *h_payto,
uint64_t *process_row);
+
#endif
diff --git a/src/exchangedb/pg_lookup_auditor_status.c b/src/exchangedb/pg_lookup_auditor_status.c
index 5e62bfa9e..91afe6eaa 100644
--- a/src/exchangedb/pg_lookup_auditor_status.c
+++ b/src/exchangedb/pg_lookup_auditor_status.c
@@ -46,7 +46,7 @@ TEH_PG_lookup_auditor_status (
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_lookup_auditor_status() */
+ /* Used in #postgres_lookup_auditor_status() */
PREPARE (pg,
"lookup_auditor_status",
"SELECT"
diff --git a/src/exchangedb/pg_lookup_auditor_timestamp.c b/src/exchangedb/pg_lookup_auditor_timestamp.c
index 3a4bd6bed..eb85876fe 100644
--- a/src/exchangedb/pg_lookup_auditor_timestamp.c
+++ b/src/exchangedb/pg_lookup_auditor_timestamp.c
@@ -43,7 +43,7 @@ TEH_PG_lookup_auditor_timestamp (
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_lookup_auditor_timestamp() */
+ /* Used in #postgres_lookup_auditor_timestamp() */
PREPARE (pg,
"lookup_auditor_timestamp",
"SELECT"
diff --git a/src/exchangedb/pg_lookup_denomination_key.c b/src/exchangedb/pg_lookup_denomination_key.c
index 36ada96e4..a358528ad 100644
--- a/src/exchangedb/pg_lookup_denomination_key.c
+++ b/src/exchangedb/pg_lookup_denomination_key.c
@@ -60,7 +60,6 @@ TEH_PG_lookup_denomination_key (
GNUNET_PQ_result_spec_end
};
- /* used in #postgres_lookup_denomination_key() */
PREPARE (pg,
"lookup_denomination_key",
"SELECT"
@@ -68,16 +67,11 @@ TEH_PG_lookup_denomination_key (
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val"
- ",coin_frac"
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin"
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",age_mask"
" FROM denominations"
" WHERE denom_pub_hash=$1;");
diff --git a/src/exchangedb/pg_lookup_global_fee_by_time.c b/src/exchangedb/pg_lookup_global_fee_by_time.c
index 0119c2cd1..c3a6ec8b7 100644
--- a/src/exchangedb/pg_lookup_global_fee_by_time.c
+++ b/src/exchangedb/pg_lookup_global_fee_by_time.c
@@ -165,12 +165,9 @@ TEH_PG_lookup_global_fee_by_time (
PREPARE (pg,
"lookup_global_fee_by_time",
"SELECT"
- " history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ " history_fee"
+ ",account_fee"
+ ",purse_fee"
",purse_timeout"
",history_expiration"
",purse_account_limit"
diff --git a/src/exchangedb/pg_lookup_global_fee_by_time.h b/src/exchangedb/pg_lookup_global_fee_by_time.h
index 9ac7d7dcd..c5ff95fc6 100644
--- a/src/exchangedb/pg_lookup_global_fee_by_time.h
+++ b/src/exchangedb/pg_lookup_global_fee_by_time.h
@@ -48,4 +48,5 @@ TEH_PG_lookup_global_fee_by_time (
struct GNUNET_TIME_Relative *purse_timeout,
struct GNUNET_TIME_Relative *history_expiration,
uint32_t *purse_account_limit);
+
#endif
diff --git a/src/exchangedb/pg_lookup_kyc_process_by_account.c b/src/exchangedb/pg_lookup_kyc_process_by_account.c
index 79a9d6c8f..b077661c5 100644
--- a/src/exchangedb/pg_lookup_kyc_process_by_account.c
+++ b/src/exchangedb/pg_lookup_kyc_process_by_account.c
@@ -60,7 +60,6 @@ TEH_PG_lookup_kyc_process_by_account (
*provider_account_id = NULL;
*provider_legitimization_id = NULL;
- /* Used in #postgres_lookup_kyc_process_by_account() */
PREPARE (pg,
"lookup_process_by_account",
"SELECT "
@@ -70,7 +69,12 @@ TEH_PG_lookup_kyc_process_by_account (
",provider_legitimization_id"
" FROM legitimization_processes"
" WHERE h_payto=$1"
- " AND provider_section=$2;");
+ " AND provider_section=$2"
+ " AND NOT finished"
+ /* Note: there *should* only be one unfinished
+ match, so this is just to be safe(r): */
+ " ORDER BY expiration_time DESC"
+ " LIMIT 1;");
return GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"lookup_process_by_account",
diff --git a/src/exchangedb/pg_lookup_kyc_process_by_account.h b/src/exchangedb/pg_lookup_kyc_process_by_account.h
index 40af6a7f6..0300b498c 100644
--- a/src/exchangedb/pg_lookup_kyc_process_by_account.h
+++ b/src/exchangedb/pg_lookup_kyc_process_by_account.h
@@ -47,4 +47,5 @@ TEH_PG_lookup_kyc_process_by_account (
struct GNUNET_TIME_Absolute *expiration,
char **provider_account_id,
char **provider_legitimization_id);
+
#endif
diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c
index 6542aa28f..6f9d76786 100644
--- a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c
+++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c
@@ -30,9 +30,11 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls,
uint64_t requirement_row,
char **requirements,
+ enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto)
{
struct PostgresClosure *pg = cls;
+ uint32_t status = TALER_AML_NORMAL;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&requirement_row),
GNUNET_PQ_query_param_end
@@ -42,19 +44,28 @@ TEH_PG_lookup_kyc_requirement_by_row (
requirements),
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
h_payto),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("status",
+ &status),
+ NULL),
GNUNET_PQ_result_spec_end
};
-/* Used in #postgres_lookup_kyc_requirement_by_row() */
+ enum GNUNET_DB_QueryStatus qs;
+
PREPARE (pg,
"lookup_legitimization_requirement_by_row",
"SELECT "
- " required_checks"
- ",h_payto"
- " FROM legitimization_requirements"
+ " lr.required_checks"
+ ",lr.h_payto"
+ ",aml.status"
+ " FROM legitimization_requirements lr"
+ " LEFT JOIN aml_status aml USING (h_payto)"
" WHERE legitimization_requirement_serial_id=$1;");
- return GNUNET_PQ_eval_prepared_singleton_select (
+ qs = GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
"lookup_legitimization_requirement_by_row",
params,
rs);
+ *aml_status = (enum TALER_AmlDecisionState) status;
+ return qs;
}
diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.h b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h
index 12d726187..3d223c985 100644
--- a/src/exchangedb/pg_lookup_kyc_requirement_by_row.h
+++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h
@@ -32,6 +32,7 @@
* @param cls closure
* @param requirement_row identifies requirement to look up
* @param[out] requirements provider that must be checked
+ * @param[out] aml_status set to the AML status of the account
* @param[out] h_payto account that must be KYC'ed
* @return database transaction status
*/
@@ -40,5 +41,7 @@ TEH_PG_lookup_kyc_requirement_by_row (
void *cls,
uint64_t requirement_row,
char **requirements,
+ enum TALER_AmlDecisionState *aml_status,
struct TALER_PaytoHashP *h_payto);
+
#endif
diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c
index 806896e78..fc4af32a8 100644
--- a/src/exchangedb/pg_lookup_records_by_table.c
+++ b/src/exchangedb/pg_lookup_records_by_table.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2020, 2021, 2022 Taler Systems SA
+ Copyright (C) 2020-2023 Taler Systems SA
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
@@ -21,6 +21,7 @@
* @file exchangedb/pg_lookup_records_by_table.c
* @brief implementation of lookup_records_by_table
* @author Christian Grothoff
+ * @author Özgür Kesim
*/
#include "platform.h"
#include "taler_error_codes.h"
@@ -28,6 +29,7 @@
#include "taler_pq_lib.h"
#include "pg_lookup_records_by_table.h"
#include "pg_helper.h"
+#include <gnunet/gnunet_pq_lib.h>
/**
@@ -232,6 +234,114 @@ lrbt_cb_table_wire_targets (void *cls,
/**
+ * Function called with legitimization_processes table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_legitimization_processes (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "h_payto",
+ &td.details.legitimization_processes.h_payto),
+ GNUNET_PQ_result_spec_timestamp (
+ "expiration_time",
+ &td.details.legitimization_processes.expiration_time),
+ GNUNET_PQ_result_spec_string (
+ "provider_section",
+ &td.details.legitimization_processes.provider_section),
+ GNUNET_PQ_result_spec_string (
+ "provider_user_id",
+ &td.details.legitimization_processes.provider_user_id),
+ GNUNET_PQ_result_spec_string (
+ "provider_legitimization_id",
+ &td.details.legitimization_processes.provider_legitimization_id),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with legitimization_requirements table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_legitimization_requirements (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_LEGITIMIZATION_REQUIREMENTS
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "h_payto",
+ &td.details.legitimization_requirements.h_payto),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_pub",
+ &td.details.legitimization_requirements.reserve_pub),
+ &td.details.legitimization_requirements.no_reserve_pub),
+ GNUNET_PQ_result_spec_string (
+ "required_checks",
+ &td.details.legitimization_requirements.required_checks),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
* Function called with reserves table entries.
*
* @param cls closure
@@ -401,6 +511,123 @@ lrbt_cb_table_reserves_close (void *cls,
/**
+ * Function called with reserves_open_requests table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_reserves_open_requests (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_pub",
+ &td.details.reserves_open_requests.reserve_pub),
+ GNUNET_PQ_result_spec_timestamp (
+ "request_timestamp",
+ &td.details.reserves_open_requests.request_timestamp),
+ GNUNET_PQ_result_spec_timestamp (
+ "expiration_date",
+ &td.details.reserves_open_requests.expiration_date),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_sig",
+ &td.details.reserves_open_requests.reserve_sig),
+ TALER_PQ_RESULT_SPEC_AMOUNT (
+ "reserve_payment",
+ &td.details.reserves_open_requests.reserve_payment),
+ GNUNET_PQ_result_spec_uint32 (
+ "requested_purse_limit",
+ &td.details.reserves_open_requests.requested_purse_limit),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with reserves_open_deposits table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_reserves_open_deposits (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("serial",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_sig",
+ &td.details.reserves_open_deposits.reserve_sig),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_pub",
+ &td.details.reserves_open_deposits.reserve_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "coin_pub",
+ &td.details.reserves_open_deposits.coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "coin_sig",
+ &td.details.reserves_open_deposits.coin_sig),
+ TALER_PQ_RESULT_SPEC_AMOUNT (
+ "contribution",
+ &td.details.reserves_open_deposits.contribution),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
* Function called with reserves_out table entries.
*
* @param cls closure
@@ -897,9 +1124,9 @@ lrbt_cb_table_refresh_transfer_keys (void *cls,
ctx->error = true;
return;
}
- memcpy (&td.details.refresh_transfer_keys.tprivs[0],
- tpriv,
- tpriv_size);
+ GNUNET_memcpy (&td.details.refresh_transfer_keys.tprivs[0],
+ tpriv,
+ tpriv_size);
ctx->cb (ctx->cb_cls,
&td);
GNUNET_PQ_cleanup_result (rs);
@@ -908,77 +1135,124 @@ lrbt_cb_table_refresh_transfer_keys (void *cls,
/**
- * Function called with deposits table entries.
+ * Function called with batch deposits table entries.
*
* @param cls closure
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lrbt_cb_table_deposits (void *cls,
- PGresult *result,
- unsigned int num_results)
+lrbt_cb_table_batch_deposits (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
- struct PostgresClosure *pg = ctx->pg;
struct TALER_EXCHANGEDB_TableData td = {
- .table = TALER_EXCHANGEDB_RT_DEPOSITS
+ .table = TALER_EXCHANGEDB_RT_BATCH_DEPOSITS
};
for (unsigned int i = 0; i<num_results; i++)
{
- bool no_policy;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"serial",
&td.serial),
GNUNET_PQ_result_spec_uint64 (
"shard",
- &td.details.deposits.shard),
- GNUNET_PQ_result_spec_uint64 (
- "known_coin_id",
- &td.details.deposits.known_coin_id),
+ &td.details.batch_deposits.shard),
GNUNET_PQ_result_spec_auto_from_type (
- "coin_pub",
- &td.details.deposits.coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT (
- "amount_with_fee",
- &td.details.deposits.amount_with_fee),
+ "merchant_pub",
+ &td.details.batch_deposits.merchant_pub),
GNUNET_PQ_result_spec_timestamp (
"wallet_timestamp",
- &td.details.deposits.wallet_timestamp),
+ &td.details.batch_deposits.wallet_timestamp),
GNUNET_PQ_result_spec_timestamp (
"exchange_timestamp",
- &td.details.deposits.exchange_timestamp),
+ &td.details.batch_deposits.exchange_timestamp),
GNUNET_PQ_result_spec_timestamp (
"refund_deadline",
- &td.details.deposits.refund_deadline),
+ &td.details.batch_deposits.refund_deadline),
GNUNET_PQ_result_spec_timestamp (
"wire_deadline",
- &td.details.deposits.wire_deadline),
- GNUNET_PQ_result_spec_auto_from_type (
- "merchant_pub",
- &td.details.deposits.merchant_pub),
+ &td.details.batch_deposits.wire_deadline),
GNUNET_PQ_result_spec_auto_from_type (
"h_contract_terms",
- &td.details.deposits.h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type (
- "coin_sig",
- &td.details.deposits.coin_sig),
+ &td.details.batch_deposits.h_contract_terms),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type (
+ "wallet_data_hash",
+ &td.details.batch_deposits.wallet_data_hash),
+ &td.details.batch_deposits.no_wallet_data_hash),
GNUNET_PQ_result_spec_auto_from_type (
"wire_salt",
- &td.details.deposits.wire_salt),
+ &td.details.batch_deposits.wire_salt),
GNUNET_PQ_result_spec_auto_from_type (
"wire_target_h_payto",
- &td.details.deposits.wire_target_h_payto),
+ &td.details.batch_deposits.wire_target_h_payto),
GNUNET_PQ_result_spec_auto_from_type (
"policy_blocked",
- &td.details.deposits.policy_blocked),
+ &td.details.batch_deposits.policy_blocked),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint64 (
"policy_details_serial_id",
- &td.details.deposits.policy_details_serial_id),
- &no_policy),
+ &td.details.batch_deposits.policy_details_serial_id),
+ &td.details.batch_deposits.no_policy_details),
+ GNUNET_PQ_result_spec_end
+ };
+
+ td.details.batch_deposits.policy_details_serial_id = 0;
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with coin deposits table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_coin_deposits (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_COIN_DEPOSITS
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "serial",
+ &td.serial),
+ GNUNET_PQ_result_spec_uint64 (
+ "batch_deposit_serial_id",
+ &td.details.coin_deposits.batch_deposit_serial_id),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "coin_pub",
+ &td.details.coin_deposits.coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "coin_sig",
+ &td.details.coin_deposits.coin_sig),
+ TALER_PQ_RESULT_SPEC_AMOUNT (
+ "amount_with_fee",
+ &td.details.coin_deposits.amount_with_fee),
GNUNET_PQ_result_spec_end
};
@@ -1035,8 +1309,8 @@ lrbt_cb_table_refunds (void *cls,
"amount_with_fee",
&td.details.refunds.amount_with_fee),
GNUNET_PQ_result_spec_uint64 (
- "deposit_serial_id",
- &td.details.refunds.deposit_serial_id),
+ "batch_deposit_serial_id",
+ &td.details.refunds.batch_deposit_serial_id),
GNUNET_PQ_result_spec_end
};
@@ -1137,8 +1411,8 @@ lrbt_cb_table_aggregation_tracking (void *cls,
"serial",
&td.serial),
GNUNET_PQ_result_spec_uint64 (
- "deposit_serial_id",
- &td.details.aggregation_tracking.deposit_serial_id),
+ "batch_deposit_serial_id",
+ &td.details.aggregation_tracking.batch_deposit_serial_id),
GNUNET_PQ_result_spec_auto_from_type (
"wtid_raw",
&td.details.aggregation_tracking.wtid_raw),
@@ -2296,6 +2570,313 @@ lrbt_cb_table_profit_drains (void *cls,
/**
+ * Function called with aml_staff table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_aml_staff (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_AML_STAFF
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "aml_staff_uuid",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "decider_pub",
+ &td.details.aml_staff.decider_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "master_sig",
+ &td.details.aml_staff.master_sig),
+ GNUNET_PQ_result_spec_string (
+ "decider_name",
+ &td.details.aml_staff.decider_name),
+ GNUNET_PQ_result_spec_bool (
+ "is_active",
+ &td.details.aml_staff.is_active),
+ GNUNET_PQ_result_spec_bool (
+ "read_only",
+ &td.details.aml_staff.read_only),
+ GNUNET_PQ_result_spec_timestamp (
+ "last_change",
+ &td.details.aml_staff.last_change),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with aml_history table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_aml_history (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_AML_HISTORY
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ uint32_t status32;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "aml_history_serial_id",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "h_payto",
+ &td.details.aml_history.h_payto),
+ TALER_PQ_RESULT_SPEC_AMOUNT (
+ "new_threshold",
+ &td.details.aml_history.new_threshold),
+ GNUNET_PQ_result_spec_uint32 (
+ "new_status",
+ &status32),
+ GNUNET_PQ_result_spec_timestamp (
+ "decision_time",
+ &td.details.aml_history.decision_time),
+ GNUNET_PQ_result_spec_string (
+ "justification",
+ &td.details.aml_history.justification),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string (
+ "kyc_requirements",
+ &td.details.aml_history.kyc_requirements),
+ NULL),
+ GNUNET_PQ_result_spec_uint64 (
+ "kyc_req_row",
+ &td.details.aml_history.kyc_req_row),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "decider_pub",
+ &td.details.aml_history.decider_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "decider_sig",
+ &td.details.aml_history.decider_sig),
+ GNUNET_PQ_result_spec_end
+ };
+
+ td.details.aml_history.kyc_requirements = NULL;
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ td.details.aml_history.new_status
+ = (enum TALER_AmlDecisionState) status32;
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with kyc_attributes table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_kyc_attributes (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "kyc_attributes_serial_id",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "h_payto",
+ &td.details.kyc_attributes.h_payto),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "kyc_prox",
+ &td.details.kyc_attributes.kyc_prox),
+ GNUNET_PQ_result_spec_string (
+ "provider",
+ &td.details.kyc_attributes.provider),
+ GNUNET_PQ_result_spec_timestamp (
+ "collection_time",
+ &td.details.kyc_attributes.collection_time),
+ GNUNET_PQ_result_spec_timestamp (
+ "expiration_time",
+ &td.details.kyc_attributes.expiration_time),
+ GNUNET_PQ_result_spec_variable_size (
+ "encrypted_attributes",
+ &td.details.kyc_attributes.encrypted_attributes,
+ &td.details.kyc_attributes.encrypted_attributes_size),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with purse_deletion table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_purse_deletion (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_PURSE_DELETION
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "purse_deletion_serial_id",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "purse_sig",
+ &td.details.purse_deletion.purse_sig),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "purse_pub",
+ &td.details.purse_deletion.purse_pub),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Function called with age_withdraw table entries.
+ *
+ * @param cls closure
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lrbt_cb_table_age_withdraw (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupRecordsByTableContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_EXCHANGEDB_TableData td = {
+ .table = TALER_EXCHANGEDB_RT_AGE_WITHDRAW
+ };
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 (
+ "age_withdraw_id",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "h_commitment",
+ &td.details.age_withdraw.h_commitment),
+ GNUNET_PQ_result_spec_uint16 (
+ "max_age",
+ &td.details.age_withdraw.max_age),
+ TALER_PQ_RESULT_SPEC_AMOUNT (
+ "amount_with_fee",
+ &td.details.age_withdraw.amount_with_fee),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_pub",
+ &td.details.age_withdraw.reserve_pub),
+ GNUNET_PQ_result_spec_auto_from_type (
+ "reserve_sig",
+ &td.details.age_withdraw.reserve_sig),
+ GNUNET_PQ_result_spec_uint32 (
+ "noreveal_index",
+ &td.details.age_withdraw.noreveal_index),
+ /* TODO[oec]: more fields! */
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->error = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ &td);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
* Assign statement to @a n and PREPARE
* @a sql under name @a n.
*/
@@ -2321,8 +2902,8 @@ TEH_PG_lookup_records_by_table (void *cls,
.cb = cb,
.cb_cls = cb_cls
};
- GNUNET_PQ_PostgresResultHandler rh;
- const char *statement;
+ GNUNET_PQ_PostgresResultHandler rh = NULL;
+ const char *statement = NULL;
enum GNUNET_DB_QueryStatus qs;
switch (table)
@@ -2338,16 +2919,11 @@ TEH_PG_lookup_records_by_table (void *cls,
",expire_withdraw"
",expire_deposit"
",expire_legal"
- ",coin_val"
- ",coin_frac"
- ",fee_withdraw_val"
- ",fee_withdraw_frac"
- ",fee_deposit_val"
- ",fee_deposit_frac"
- ",fee_refresh_val"
- ",fee_refresh_frac"
- ",fee_refund_val"
- ",fee_refund_frac"
+ ",coin"
+ ",fee_withdraw"
+ ",fee_deposit"
+ ",fee_refresh"
+ ",fee_refund"
",age_mask"
" FROM denominations"
" WHERE denominations_serial > $1"
@@ -2375,6 +2951,33 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY wire_target_serial_id ASC;");
rh = &lrbt_cb_table_wire_targets;
break;
+ case TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES:
+ XPREPARE ("select_above_serial_by_table_legitimization_processes",
+ "SELECT"
+ " legitimization_process_serial_id AS serial"
+ ",h_payto"
+ ",reserve_pub"
+ ",expiration_time"
+ ",provider_section"
+ ",provider_user_id"
+ ",provider_legitimization_id"
+ " FROM legitimization_processes"
+ " WHERE legitimization_process_serial_id > $1"
+ " ORDER BY legitimization_process_serial_id ASC;");
+ rh = &lrbt_cb_table_legitimization_processes;
+ break;
+ case TALER_EXCHANGEDB_RT_LEGITIMIZATION_REQUIREMENTS:
+ XPREPARE ("select_above_serial_by_table_legitimization_requirements",
+ "SELECT"
+ " legitimization_requirement_serial_id AS serial"
+ ",h_payto"
+ ",reserve_pub"
+ ",required_checks"
+ " FROM legitimization_requirements"
+ " WHERE legitimization_requirement_serial_id > $1"
+ " ORDER BY legitimization_requirement_serial_id ASC;");
+ rh = &lrbt_cb_table_legitimization_requirements;
+ break;
case TALER_EXCHANGEDB_RT_RESERVES:
XPREPARE ("select_above_serial_by_table_reserves",
"SELECT"
@@ -2393,8 +2996,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" reserve_in_serial_id AS serial"
",reserve_pub"
",wire_reference"
- ",credit_val"
- ",credit_frac"
+ ",credit"
",wire_source_h_payto"
",exchange_account_section"
",execution_date"
@@ -2411,15 +3013,42 @@ TEH_PG_lookup_records_by_table (void *cls,
",execution_date"
",wtid"
",wire_target_h_payto"
- ",amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",amount"
+ ",closing_fee"
" FROM reserves_close"
" WHERE close_uuid > $1"
" ORDER BY close_uuid ASC;");
rh = &lrbt_cb_table_reserves_close;
break;
+ case TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS:
+ XPREPARE ("select_above_serial_by_table_reserves_open_requests",
+ "SELECT"
+ " open_request_uuid AS serial"
+ ",reserve_pub"
+ ",request_timestamp"
+ ",expiration_date"
+ ",reserve_sig"
+ ",reserve_payment"
+ ",requested_purse_limit"
+ " FROM reserves_open_requests"
+ " WHERE open_request_uuid > $1"
+ " ORDER BY open_request_uuid ASC;");
+ rh = &lrbt_cb_table_reserves_open_requests;
+ break;
+ case TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS:
+ XPREPARE ("select_above_serial_by_table_reserves_open_deposits",
+ "SELECT"
+ " reserves_open_deposit_uuid AS serial"
+ ",reserve_sig"
+ ",reserve_pub"
+ ",coin_pub"
+ ",coin_sig"
+ ",contribution"
+ " FROM reserves_open_deposits"
+ " WHERE reserves_open_deposit_uuid > $1"
+ " ORDER BY reserves_open_deposit_uuid ASC;");
+ rh = &lrbt_cb_table_reserves_open_deposits;
+ break;
case TALER_EXCHANGEDB_RT_RESERVES_OUT:
XPREPARE ("select_above_serial_by_table_reserves_out",
"SELECT"
@@ -2430,8 +3059,7 @@ TEH_PG_lookup_records_by_table (void *cls,
",reserve_uuid"
",reserve_sig"
",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
" FROM reserves_out"
" JOIN reserves USING (reserve_uuid)"
" WHERE reserve_out_serial_id > $1"
@@ -2507,8 +3135,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" melt_serial_id AS serial"
",rc"
",old_coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",old_coin_pub"
" FROM refresh_commitments"
@@ -2544,31 +3171,40 @@ TEH_PG_lookup_records_by_table (void *cls,
" ORDER BY rtc_serial ASC;");
rh = &lrbt_cb_table_refresh_transfer_keys;
break;
- case TALER_EXCHANGEDB_RT_DEPOSITS:
- XPREPARE ("select_above_serial_by_table_deposits",
+ case TALER_EXCHANGEDB_RT_BATCH_DEPOSITS:
+ XPREPARE ("select_above_serial_by_table_batch_deposits",
"SELECT"
- " deposit_serial_id AS serial"
+ " batch_deposit_serial_id AS serial"
",shard"
- ",coin_pub"
- ",known_coin_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",merchant_pub"
",wallet_timestamp"
",exchange_timestamp"
",refund_deadline"
",wire_deadline"
- ",merchant_pub"
",h_contract_terms"
- ",coin_sig"
+ ",wallet_data_hash"
",wire_salt"
",wire_target_h_payto"
",done"
",policy_blocked"
",policy_details_serial_id"
- " FROM deposits"
- " WHERE deposit_serial_id > $1"
- " ORDER BY deposit_serial_id ASC;");
- rh = &lrbt_cb_table_deposits;
+ " FROM batch_deposits"
+ " WHERE batch_deposit_serial_id > $1"
+ " ORDER BY batch_deposit_serial_id ASC;");
+ rh = &lrbt_cb_table_batch_deposits;
+ break;
+ case TALER_EXCHANGEDB_RT_COIN_DEPOSITS:
+ XPREPARE ("select_above_serial_by_table_coin_deposits",
+ "SELECT"
+ " coin_deposit_serial_id AS serial"
+ ",batch_deposit_serial_id"
+ ",coin_pub"
+ ",coin_sig"
+ ",amount_with_fee"
+ " FROM coin_deposits"
+ " WHERE coin_deposit_serial_id > $1"
+ " ORDER BY coin_deposit_serial_id ASC;");
+ rh = &lrbt_cb_table_coin_deposits;
break;
case TALER_EXCHANGEDB_RT_REFUNDS:
XPREPARE ("select_above_serial_by_table_refunds",
@@ -2577,9 +3213,8 @@ TEH_PG_lookup_records_by_table (void *cls,
",coin_pub"
",merchant_sig"
",rtransaction_id"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_serial_id"
+ ",amount_with_fee"
+ ",batch_deposit_serial_id"
" FROM refunds"
" WHERE refund_serial_id > $1"
" ORDER BY refund_serial_id ASC;");
@@ -2593,8 +3228,7 @@ TEH_PG_lookup_records_by_table (void *cls,
",wtid_raw"
",wire_target_h_payto"
",exchange_account_section"
- ",amount_val"
- ",amount_frac"
+ ",amount"
" FROM wire_out"
" WHERE wireout_uuid > $1"
" ORDER BY wireout_uuid ASC;");
@@ -2604,7 +3238,7 @@ TEH_PG_lookup_records_by_table (void *cls,
XPREPARE ("select_above_serial_by_table_aggregation_tracking",
"SELECT"
" aggregation_serial_id AS serial"
- ",deposit_serial_id"
+ ",batch_deposit_serial_id"
",wtid_raw"
" FROM aggregation_tracking"
" WHERE aggregation_serial_id > $1"
@@ -2618,10 +3252,8 @@ TEH_PG_lookup_records_by_table (void *cls,
",wire_method"
",start_date"
",end_date"
- ",wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",wire_fee"
+ ",closing_fee"
",master_sig"
" FROM wire_fee"
" WHERE wire_fee_serial > $1"
@@ -2634,12 +3266,9 @@ TEH_PG_lookup_records_by_table (void *cls,
" global_fee_serial AS serial"
",start_date"
",end_date"
- ",history_fee_val"
- ",history_fee_frac"
- ",account_fee_val"
- ",account_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",history_fee"
+ ",account_fee"
+ ",purse_fee"
",purse_timeout"
",history_expiration"
",purse_account_limit"
@@ -2655,8 +3284,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" recoup_uuid AS serial"
",coin_sig"
",coin_blind"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",recoup_timestamp"
",coin_pub"
",reserve_out_serial_id"
@@ -2671,8 +3299,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" recoup_refresh_uuid AS serial"
",coin_sig"
",coin_blind"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",recoup_timestamp"
",coin_pub"
",known_coin_id"
@@ -2705,10 +3332,8 @@ TEH_PG_lookup_records_by_table (void *cls,
",h_contract_terms"
",age_limit"
",flags"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",purse_fee_val"
- ",purse_fee_frac"
+ ",amount_with_fee"
+ ",purse_fee"
",purse_sig"
" FROM purse_requests"
" WHERE purse_requests_serial_id > $1"
@@ -2748,8 +3373,7 @@ TEH_PG_lookup_records_by_table (void *cls,
",partner_serial_id"
",purse_pub"
",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",coin_sig"
" FROM purse_deposits"
" WHERE purse_deposit_serial_id > $1"
@@ -2776,8 +3400,7 @@ TEH_PG_lookup_records_by_table (void *cls,
",reserve_pub"
",request_timestamp"
",reserve_sig"
- ",history_fee_val"
- ",history_fee_frac"
+ ",history_fee"
" FROM history_requests"
" WHERE history_request_serial_id > $1"
" ORDER BY history_request_serial_id ASC;");
@@ -2790,8 +3413,7 @@ TEH_PG_lookup_records_by_table (void *cls,
",reserve_pub"
",close_timestamp"
",reserve_sig"
- ",close_val"
- ",close_frac"
+ ",close"
" FROM close_requests"
" WHERE close_request_serial_id > $1"
" ORDER BY close_request_serial_id ASC;");
@@ -2803,8 +3425,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" wad_out_serial_id"
",wad_id"
",partner_serial_id"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",execution_time"
" FROM wads_out"
" WHERE wad_out_serial_id > $1"
@@ -2820,12 +3441,9 @@ TEH_PG_lookup_records_by_table (void *cls,
",h_contract"
",purse_expiration"
",merge_timestamp"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wad_fee_val"
- ",wad_fee_frac"
- ",deposit_fees_val"
- ",deposit_fees_frac"
+ ",amount_with_fee"
+ ",wad_fee"
+ ",deposit_fees"
",reserve_sig"
",purse_sig"
" FROM wad_out_entries"
@@ -2839,8 +3457,7 @@ TEH_PG_lookup_records_by_table (void *cls,
" wad_in_serial_id"
",wad_id"
",origin_exchange_url"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",arrival_time"
" FROM wads_in"
" WHERE wad_in_serial_id > $1"
@@ -2856,12 +3473,9 @@ TEH_PG_lookup_records_by_table (void *cls,
",h_contract"
",purse_expiration"
",merge_timestamp"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wad_fee_val"
- ",wad_fee_frac"
- ",deposit_fees_val"
- ",deposit_fees_frac"
+ ",amount_with_fee"
+ ",wad_fee"
+ ",deposit_fees"
",reserve_sig"
",purse_sig"
" FROM wad_in_entries"
@@ -2877,15 +3491,92 @@ TEH_PG_lookup_records_by_table (void *cls,
",account_section"
",payto_uri"
",trigger_date"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",master_sig"
" FROM profit_drains"
" WHERE profit_drain_serial_id > $1"
" ORDER BY profit_drain_serial_id ASC;");
rh = &lrbt_cb_table_profit_drains;
break;
- default:
+
+ case TALER_EXCHANGEDB_RT_AML_STAFF:
+ XPREPARE ("select_above_serial_by_table_aml_staff",
+ "SELECT"
+ " aml_staff_uuid"
+ ",decider_pub"
+ ",master_sig"
+ ",decider_name"
+ ",is_active"
+ ",read_only"
+ ",last_change"
+ " FROM aml_staff"
+ " WHERE aml_staff_uuid > $1"
+ " ORDER BY aml_staff_uuid ASC;");
+ rh = &lrbt_cb_table_aml_staff;
+ break;
+ case TALER_EXCHANGEDB_RT_AML_HISTORY:
+ XPREPARE ("select_above_serial_by_table_aml_history",
+ "SELECT"
+ " aml_history_serial_id"
+ ",h_payto"
+ ",new_threshold"
+ ",new_status"
+ ",decision_time"
+ ",justification"
+ ",kyc_requirements"
+ ",kyc_req_row"
+ ",decider_pub"
+ ",decider_sig"
+ " FROM aml_history"
+ " WHERE aml_history_serial_id > $1"
+ " ORDER BY aml_history_serial_id ASC;");
+ rh = &lrbt_cb_table_aml_history;
+ break;
+ case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
+ XPREPARE ("select_above_serial_by_table_kyc_attributes",
+ "SELECT"
+ " kyc_attributes_serial_id"
+ ",h_payto"
+ ",kyc_prox"
+ ",provider"
+ ",collection_time"
+ ",expiration_time"
+ ",encrypted_attributes"
+ " FROM kyc_attributes"
+ " WHERE kyc_attributes_serial_id > $1"
+ " ORDER BY kyc_attributes_serial_id ASC;");
+ rh = &lrbt_cb_table_kyc_attributes;
+ break;
+ case TALER_EXCHANGEDB_RT_PURSE_DELETION:
+ XPREPARE ("select_above_serial_by_table_purse_deletion",
+ "SELECT"
+ " purse_deletion_serial_id"
+ ",purse_pub"
+ ",purse_sig"
+ " FROM purse_deletion"
+ " WHERE purse_deletion_serial_id > $1"
+ " ORDER BY purse_deletion_serial_id ASC;");
+ rh = &lrbt_cb_table_purse_deletion;
+ break;
+ case TALER_EXCHANGEDB_RT_AGE_WITHDRAW:
+ XPREPARE ("select_above_serial_by_table_age_withdraw",
+ "SELECT"
+ " age_withdraw_id"
+ ",h_commitment"
+ ",amount_with_fee"
+ ",max_age"
+ ",reserve_pub"
+ ",reserve_sig"
+ ",noreveal_index"
+ " FROM age_withdraw"
+ " WHERE age_withdraw_id > $1"
+ " ORDER BY age_withdraw_id ASC;");
+ /* TODO[oec]: MORE FIELDS! */
+ rh = &lrbt_cb_table_age_withdraw;
+ break;
+ }
+ if (NULL == rh)
+ {
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
diff --git a/src/exchangedb/pg_lookup_serial_by_table.c b/src/exchangedb/pg_lookup_serial_by_table.c
index 7e150cd28..9fda7ddf8 100644
--- a/src/exchangedb/pg_lookup_serial_by_table.c
+++ b/src/exchangedb/pg_lookup_serial_by_table.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -205,12 +205,20 @@ TEH_PG_lookup_serial_by_table (void *cls,
" ORDER BY rtc_serial DESC"
" LIMIT 1;");
break;
- case TALER_EXCHANGEDB_RT_DEPOSITS:
- XPREPARE ("select_serial_by_table_deposits",
+ case TALER_EXCHANGEDB_RT_BATCH_DEPOSITS:
+ XPREPARE ("select_serial_by_table_batch_deposits",
"SELECT"
- " deposit_serial_id AS serial"
- " FROM deposits"
- " ORDER BY deposit_serial_id DESC"
+ " batch_deposit_serial_id AS serial"
+ " FROM batch_deposits"
+ " ORDER BY batch_deposit_serial_id DESC"
+ " LIMIT 1;");
+ break;
+ case TALER_EXCHANGEDB_RT_COIN_DEPOSITS:
+ XPREPARE ("select_serial_by_table_coin_deposits",
+ "SELECT"
+ " coin_deposit_serial_id AS serial"
+ " FROM coin_deposits"
+ " ORDER BY coin_deposit_serial_id DESC"
" LIMIT 1;");
break;
case TALER_EXCHANGEDB_RT_REFUNDS:
@@ -390,6 +398,51 @@ TEH_PG_lookup_serial_by_table (void *cls,
" LIMIT 1;");
statement = "select_serial_by_table_profit_drains";
break;
+ case TALER_EXCHANGEDB_RT_AML_STAFF:
+ XPREPARE ("select_serial_by_table_aml_staff",
+ "SELECT"
+ " aml_staff_uuid AS serial"
+ " FROM aml_staff"
+ " ORDER BY aml_staff_uuid DESC"
+ " LIMIT 1;");
+ statement = "select_serial_by_table_aml_staff";
+ break;
+ case TALER_EXCHANGEDB_RT_AML_HISTORY:
+ XPREPARE ("select_serial_by_table_aml_history",
+ "SELECT"
+ " aml_history_serial_id AS serial"
+ " FROM aml_history"
+ " ORDER BY aml_history_serial_id DESC"
+ " LIMIT 1;");
+ statement = "select_serial_by_table_aml_history";
+ break;
+ case TALER_EXCHANGEDB_RT_KYC_ATTRIBUTES:
+ XPREPARE ("select_serial_by_table_kyc_attributes",
+ "SELECT"
+ " kyc_attributes_serial_id AS serial"
+ " FROM kyc_attributes"
+ " ORDER BY kyc_attributes_serial_id DESC"
+ " LIMIT 1;");
+ statement = "select_serial_by_table_kyc_attributes";
+ break;
+ case TALER_EXCHANGEDB_RT_PURSE_DELETION:
+ XPREPARE ("select_serial_by_table_purse_deletion",
+ "SELECT"
+ " purse_deletion_serial_id AS serial"
+ " FROM purse_deletion"
+ " ORDER BY purse_deletion_serial_id DESC"
+ " LIMIT 1;");
+ statement = "select_serial_by_table_purse_deletion";
+ break;
+ case TALER_EXCHANGEDB_RT_AGE_WITHDRAW:
+ XPREPARE ("select_serial_by_table_age_withdraw",
+ "SELECT"
+ " age_withdraw_id AS serial"
+ " FROM age_withdraw"
+ " ORDER BY age_withdraw_id DESC"
+ " LIMIT 1;");
+ statement = "select_serial_by_table_age_withdraw";
+ break;
}
if (NULL == statement)
{
diff --git a/src/exchangedb/pg_lookup_signing_key.c b/src/exchangedb/pg_lookup_signing_key.c
index 3f31a6f49..3803d114f 100644
--- a/src/exchangedb/pg_lookup_signing_key.c
+++ b/src/exchangedb/pg_lookup_signing_key.c
@@ -62,4 +62,3 @@ TEH_PG_lookup_signing_key (
params,
rs);
}
-
diff --git a/src/exchangedb/pg_lookup_transfer_by_deposit.c b/src/exchangedb/pg_lookup_transfer_by_deposit.c
index 686b67cc4..192556130 100644
--- a/src/exchangedb/pg_lookup_transfer_by_deposit.c
+++ b/src/exchangedb/pg_lookup_transfer_by_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
enum GNUNET_DB_QueryStatus
TEH_PG_lookup_transfer_by_deposit (
void *cls,
@@ -39,7 +38,8 @@ TEH_PG_lookup_transfer_by_deposit (
struct GNUNET_TIME_Timestamp *exec_time,
struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee,
- struct TALER_EXCHANGEDB_KycStatus *kyc)
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ enum TALER_AmlDecisionState *aml_decision)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs;
@@ -71,34 +71,33 @@ TEH_PG_lookup_transfer_by_deposit (
0,
sizeof (*kyc));
/* check if the aggregation record exists and get it */
-
- /* Used in #postgres_lookup_transfer_by_deposit */
PREPARE (pg,
"lookup_deposit_wtid",
"SELECT"
- " aggregation_tracking.wtid_raw"
+ " atr.wtid_raw"
",wire_out.execution_date"
- ",dep.amount_with_fee_val"
- ",dep.amount_with_fee_frac"
- ",dep.wire_salt"
+ ",cdep.amount_with_fee"
+ ",bdep.wire_salt"
",wt.payto_uri"
- ",denom.fee_deposit_val"
- ",denom.fee_deposit_frac"
- " FROM deposits dep"
+ ",denom.fee_deposit"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
" JOIN wire_targets wt"
" USING (wire_target_h_payto)"
- " JOIN aggregation_tracking"
- " USING (deposit_serial_id)"
+ " JOIN aggregation_tracking atr"
+ " ON (cdep.batch_deposit_serial_id = atr.batch_deposit_serial_id)"
" JOIN known_coins kc"
- " ON (kc.coin_pub = dep.coin_pub)"
+ " ON (kc.coin_pub = cdep.coin_pub)"
" JOIN denominations denom"
" USING (denominations_serial)"
" JOIN wire_out"
" USING (wtid_raw)"
- " WHERE dep.coin_pub=$1"
- " AND dep.merchant_pub=$3"
- " AND dep.h_contract_terms=$2");
-
+ " WHERE cdep.coin_pub=$1"
+ " AND bdep.merchant_pub=$3"
+ " AND bdep.h_contract_terms=$2");
+ /* NOTE: above query might be more efficient if we computed the shard
+ from the merchant_pub and included that in the query */
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"lookup_deposit_wtid",
params,
@@ -110,16 +109,18 @@ TEH_PG_lookup_transfer_by_deposit (
TALER_merchant_wire_signature_hash (payto_uri,
&wire_salt,
&wh);
- GNUNET_PQ_cleanup_result (rs);
if (0 ==
GNUNET_memcmp (&wh,
h_wire))
{
*pending = false;
kyc->ok = true;
+ *aml_decision = TALER_AML_NORMAL;
+ GNUNET_PQ_cleanup_result (rs);
return qs;
}
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ GNUNET_PQ_cleanup_result (rs);
}
if (0 > qs)
return qs;
@@ -134,15 +135,29 @@ TEH_PG_lookup_transfer_by_deposit (
/* Check if transaction exists in deposits, so that we just
do not have a WTID yet. In that case, return without wtid
(by setting 'pending' true). */
+ uint32_t status32 = TALER_AML_NORMAL;
+ uint64_t aml_kyc_row = 0;
struct GNUNET_PQ_ResultSpec rs2[] = {
GNUNET_PQ_result_spec_auto_from_type ("wire_salt",
&wire_salt),
GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri),
+ /* See Postgresql bug #18380 */
+#define BUG 1
+#if BUG
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
&kyc->requirement_row),
NULL),
+#endif
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint64 ("kyc_requirement",
+ &aml_kyc_row),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("status",
+ &status32),
+ NULL),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
@@ -152,33 +167,41 @@ TEH_PG_lookup_transfer_by_deposit (
GNUNET_PQ_result_spec_end
};
- /* Fetch an existing deposit request.
- Used in #postgres_lookup_transfer_by_deposit(). */
PREPARE (pg,
"get_deposit_without_wtid",
"SELECT"
- " agt.legitimization_requirement_serial_id"
- ",dep.wire_salt"
+ " bdep.wire_salt"
",wt.payto_uri"
- ",dep.amount_with_fee_val"
- ",dep.amount_with_fee_frac"
- ",denom.fee_deposit_val"
- ",denom.fee_deposit_frac"
- ",dep.wire_deadline"
- " FROM deposits dep"
+ ",cdep.amount_with_fee"
+ ",denom.fee_deposit"
+ ",bdep.wire_deadline"
+#if BUG
+ ",agt.legitimization_requirement_serial_id"
+#endif
+ ",aml.status"
+ ",aml.kyc_requirement"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
" JOIN wire_targets wt"
" USING (wire_target_h_payto)"
" JOIN known_coins kc"
- " ON (kc.coin_pub = dep.coin_pub)"
+ " ON (kc.coin_pub = cdep.coin_pub)"
" JOIN denominations denom"
" USING (denominations_serial)"
+#if BUG
" LEFT JOIN aggregation_transient agt "
- " ON ( (dep.wire_target_h_payto = agt.wire_target_h_payto) AND"
- " (dep.merchant_pub = agt.merchant_pub) )"
- " WHERE dep.coin_pub=$1"
- " AND dep.merchant_pub=$3"
- " AND dep.h_contract_terms=$2"
+ " ON ( (bdep.wire_target_h_payto = agt.wire_target_h_payto) AND"
+ " (bdep.merchant_pub = agt.merchant_pub) )"
+#endif
+ " LEFT JOIN aml_status aml"
+ " ON (wt.wire_target_h_payto = aml.h_payto)"
+ " WHERE cdep.coin_pub=$1"
+ " AND bdep.merchant_pub=$3"
+ " AND bdep.h_contract_terms=$2"
" LIMIT 1;");
+ /* NOTE: above query might be more efficient if we computed the shard
+ from the merchant_pub and included that in the query */
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_deposit_without_wtid",
params,
@@ -187,17 +210,30 @@ TEH_PG_lookup_transfer_by_deposit (
{
struct TALER_MerchantWireHashP wh;
+ *aml_decision = (enum TALER_AmlDecisionState) status32;
if (0 == kyc->requirement_row)
kyc->ok = true; /* technically: unknown */
+ if ( (kyc->ok) &&
+ (TALER_AML_FROZEN == *aml_decision) &&
+ (0 != aml_kyc_row) )
+ {
+ /* KYC required via AML */
+ kyc->ok = false;
+ kyc->requirement_row = aml_kyc_row;
+ }
TALER_merchant_wire_signature_hash (payto_uri,
&wire_salt,
&wh);
- GNUNET_PQ_cleanup_result (rs);
if (0 !=
GNUNET_memcmp (&wh,
h_wire))
+ {
+ GNUNET_PQ_cleanup_result (rs2);
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+ GNUNET_PQ_cleanup_result (rs2);
}
+ *aml_decision = TALER_AML_NORMAL;
return qs;
}
}
diff --git a/src/exchangedb/pg_lookup_transfer_by_deposit.h b/src/exchangedb/pg_lookup_transfer_by_deposit.h
index ff5554dcc..83782d5a0 100644
--- a/src/exchangedb/pg_lookup_transfer_by_deposit.h
+++ b/src/exchangedb/pg_lookup_transfer_by_deposit.h
@@ -42,6 +42,7 @@
* @param[out] amount_with_fee set to the total deposited amount
* @param[out] deposit_fee set to how much the exchange did charge for the deposit
* @param[out] kyc set to the kyc status of the receiver (if @a pending)
+ * @param[out] aml_decision set to the AML status of the receiver
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -56,6 +57,7 @@ TEH_PG_lookup_transfer_by_deposit (
struct GNUNET_TIME_Timestamp *exec_time,
struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee,
- struct TALER_EXCHANGEDB_KycStatus *kyc);
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ enum TALER_AmlDecisionState *aml_decision);
#endif
diff --git a/src/exchangedb/pg_lookup_wire_fee_by_time.c b/src/exchangedb/pg_lookup_wire_fee_by_time.c
index 89be4087a..775232a48 100644
--- a/src/exchangedb/pg_lookup_wire_fee_by_time.c
+++ b/src/exchangedb/pg_lookup_wire_fee_by_time.c
@@ -142,10 +142,8 @@ TEH_PG_lookup_wire_fee_by_time (
PREPARE (pg,
"lookup_wire_fee_by_time",
"SELECT"
- " wire_fee_val"
- ",wire_fee_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ " wire_fee"
+ ",closing_fee"
" FROM wire_fee"
" WHERE wire_method=$1"
" AND end_date > $2"
diff --git a/src/exchangedb/pg_lookup_wire_timestamp.c b/src/exchangedb/pg_lookup_wire_timestamp.c
index 19e915d48..17dffc706 100644
--- a/src/exchangedb/pg_lookup_wire_timestamp.c
+++ b/src/exchangedb/pg_lookup_wire_timestamp.c
@@ -28,8 +28,8 @@
enum GNUNET_DB_QueryStatus
TEH_PG_lookup_wire_timestamp (void *cls,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp *last_date)
+ const char *payto_uri,
+ struct GNUNET_TIME_Timestamp *last_date)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
diff --git a/src/exchangedb/pg_lookup_wire_timestamp.h b/src/exchangedb/pg_lookup_wire_timestamp.h
index 069dd940c..f2ee117de 100644
--- a/src/exchangedb/pg_lookup_wire_timestamp.h
+++ b/src/exchangedb/pg_lookup_wire_timestamp.h
@@ -34,7 +34,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_lookup_wire_timestamp (void *cls,
- const char *payto_uri,
+ const char *payto_uri,
struct GNUNET_TIME_Timestamp *last_date);
#endif
diff --git a/src/exchangedb/pg_lookup_wire_transfer.c b/src/exchangedb/pg_lookup_wire_transfer.c
index 5d1ad25f5..7ab023fe7 100644
--- a/src/exchangedb/pg_lookup_wire_transfer.c
+++ b/src/exchangedb/pg_lookup_wire_transfer.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -82,7 +82,8 @@ handle_wt_result (void *cls,
struct TALER_DenominationPublicKey denom_pub;
char *payto_uri;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id", &rowid),
+ GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id",
+ &rowid),
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
&h_contract_terms),
GNUNET_PQ_result_spec_string ("payto_uri",
@@ -153,20 +154,20 @@ TEH_PG_lookup_wire_transfer (
"lookup_transactions",
"SELECT"
" aggregation_serial_id"
- ",deposits.h_contract_terms"
+ ",bdep.h_contract_terms"
",payto_uri"
",wire_targets.wire_target_h_payto"
",kc.coin_pub"
- ",deposits.merchant_pub"
+ ",bdep.merchant_pub"
",wire_out.execution_date"
- ",deposits.amount_with_fee_val"
- ",deposits.amount_with_fee_frac"
- ",denom.fee_deposit_val"
- ",denom.fee_deposit_frac"
+ ",cdep.amount_with_fee"
+ ",denom.fee_deposit"
",denom.denom_pub"
" FROM aggregation_tracking"
- " JOIN deposits"
- " USING (deposit_serial_id)"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
+ " JOIN coin_deposits cdep"
+ " USING (batch_deposit_serial_id)"
" JOIN wire_targets"
" USING (wire_target_h_payto)"
" JOIN known_coins kc"
diff --git a/src/exchangedb/pg_persist_policy_details.c b/src/exchangedb/pg_persist_policy_details.c
index 3bc7afa98..d97b92eac 100644
--- a/src/exchangedb/pg_persist_policy_details.c
+++ b/src/exchangedb/pg_persist_policy_details.c
@@ -39,10 +39,14 @@ TEH_PG_persist_policy_details (
GNUNET_PQ_query_param_auto_from_type (&details->hash_code),
TALER_PQ_query_param_json (details->policy_json),
GNUNET_PQ_query_param_timestamp (&details->deadline),
- TALER_PQ_query_param_amount (&details->commitment),
- TALER_PQ_query_param_amount (&details->accumulated_total),
- TALER_PQ_query_param_amount (&details->policy_fee),
- TALER_PQ_query_param_amount (&details->transferable_amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ &details->commitment),
+ TALER_PQ_query_param_amount (pg->conn,
+ &details->accumulated_total),
+ TALER_PQ_query_param_amount (pg->conn,
+ &details->policy_fee),
+ TALER_PQ_query_param_amount (pg->conn,
+ &details->transferable_amount),
GNUNET_PQ_query_param_auto_from_type (&details->fulfillment_state),
(details->no_policy_fulfillment_id)
? GNUNET_PQ_query_param_null ()
@@ -63,11 +67,10 @@ TEH_PG_persist_policy_details (
"call_insert_or_update_policy_details",
"SELECT"
" out_policy_details_serial_id AS policy_details_serial_id"
- ",out_accumulated_total_val AS accumulated_total_val"
- ",out_accumulated_total_frac AS accumulated_total_frac"
+ ",out_accumulated_total AS accumulated_total"
",out_fulfillment_state AS fulfillment_state"
" FROM exchange_do_insert_or_update_policy_details"
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9);");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"call_insert_or_update_policy_details",
params,
diff --git a/src/exchangedb/pg_persist_policy_details.h b/src/exchangedb/pg_persist_policy_details.h
index ed9fd95d8..4fe709d92 100644
--- a/src/exchangedb/pg_persist_policy_details.h
+++ b/src/exchangedb/pg_persist_policy_details.h
@@ -24,6 +24,8 @@
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
+
+
/* Persist the details to a policy in the policy_details table. If there
* already exists a policy, update the fields accordingly.
*
diff --git a/src/exchangedb/pg_profit_drains_get_pending.c b/src/exchangedb/pg_profit_drains_get_pending.c
index a7044ebb8..c844a3f38 100644
--- a/src/exchangedb/pg_profit_drains_get_pending.c
+++ b/src/exchangedb/pg_profit_drains_get_pending.c
@@ -57,7 +57,7 @@ TEH_PG_profit_drains_get_pending (
master_sig),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_profit_drains_get_pending() */
+ /* Used in #postgres_profit_drains_get_pending() */
PREPARE (pg,
"get_ready_profit_drain",
"SELECT"
@@ -66,8 +66,7 @@ TEH_PG_profit_drains_get_pending (
",account_section"
",payto_uri"
",trigger_date"
- ",amount_val"
- ",amount_frac"
+ ",amount"
",master_sig"
" FROM profit_drains"
" WHERE NOT executed"
diff --git a/src/exchangedb/pg_profit_drains_set_finished.c b/src/exchangedb/pg_profit_drains_set_finished.c
index b70af31fe..f0de27945 100644
--- a/src/exchangedb/pg_profit_drains_set_finished.c
+++ b/src/exchangedb/pg_profit_drains_set_finished.c
@@ -38,18 +38,12 @@ TEH_PG_profit_drains_set_finished (
};
PREPARE (pg,
- "drain_profit_set_finished",
- "UPDATE profit_drains"
- " SET"
- " executed=TRUE"
- " WHERE profit_drain_serial_id=$1;");
+ "drain_profit_set_finished",
+ "UPDATE profit_drains"
+ " SET"
+ " executed=TRUE"
+ " WHERE profit_drain_serial_id=$1;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"drain_profit_set_finished",
params);
}
-
-
-
-
-
-
diff --git a/src/exchangedb/pg_release_revolving_shard.c b/src/exchangedb/pg_release_revolving_shard.c
index f176972b6..43e45c4bc 100644
--- a/src/exchangedb/pg_release_revolving_shard.c
+++ b/src/exchangedb/pg_release_revolving_shard.c
@@ -27,9 +27,9 @@
enum GNUNET_DB_QueryStatus
TEH_PG_release_revolving_shard (void *cls,
- const char *job_name,
- uint32_t start_row,
- uint32_t end_row)
+ const char *job_name,
+ uint32_t start_row,
+ uint32_t end_row)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
diff --git a/src/exchangedb/pg_release_revolving_shard.h b/src/exchangedb/pg_release_revolving_shard.h
index f1712f538..ea65ab605 100644
--- a/src/exchangedb/pg_release_revolving_shard.h
+++ b/src/exchangedb/pg_release_revolving_shard.h
@@ -37,8 +37,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_release_revolving_shard (void *cls,
- const char *job_name,
- uint32_t start_row,
+ const char *job_name,
+ uint32_t start_row,
uint32_t end_row);
#endif
diff --git a/src/exchangedb/pg_reserves_get.c b/src/exchangedb/pg_reserves_get.c
index bea0022dd..cae4764a5 100644
--- a/src/exchangedb/pg_reserves_get.c
+++ b/src/exchangedb/pg_reserves_get.c
@@ -27,7 +27,7 @@
enum GNUNET_DB_QueryStatus
TEH_PG_reserves_get (void *cls,
- struct TALER_EXCHANGEDB_Reserve *reserve)
+ struct TALER_EXCHANGEDB_Reserve *reserve)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -35,7 +35,8 @@ TEH_PG_reserves_get (void *cls,
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ TALER_PQ_result_spec_amount ("current_balance",
+ pg->currency,
&reserve->balance),
GNUNET_PQ_result_spec_timestamp ("expiration_date",
&reserve->expiry),
@@ -43,12 +44,11 @@ TEH_PG_reserves_get (void *cls,
&reserve->gc),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_reserves_get() */
+ /* Used in #postgres_reserves_get() */
PREPARE (pg,
"reserves_get",
"SELECT"
- " current_balance_val"
- ",current_balance_frac"
+ " current_balance"
",expiration_date"
",gc_date"
" FROM reserves"
diff --git a/src/exchangedb/pg_reserves_get_origin.c b/src/exchangedb/pg_reserves_get_origin.c
index fd6c56586..55d3179d1 100644
--- a/src/exchangedb/pg_reserves_get_origin.c
+++ b/src/exchangedb/pg_reserves_get_origin.c
@@ -50,7 +50,7 @@ TEH_PG_reserves_get_origin (
" wire_source_h_payto"
" FROM reserves_in"
" WHERE reserve_pub=$1");
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_h_wire_source_of_reserve",
params,
rs);
diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c
index ac14cb567..21734942a 100644
--- a/src/exchangedb/pg_reserves_in_insert.c
+++ b/src/exchangedb/pg_reserves_in_insert.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -17,6 +17,7 @@
* @file exchangedb/pg_reserves_in_insert.c
* @brief Implementation of the reserves_in_insert function for Postgres
* @author Christian Grothoff
+ * @author Joseph Xu
*/
#include "platform.h"
#include "taler_error_codes.h"
@@ -50,801 +51,213 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)
.reserve_pub = *reserve_pub
};
- return GNUNET_PG_get_event_notify_channel (&rep.header);
+ return GNUNET_PQ_get_event_notify_channel (&rep.header);
}
-static void
-notify_on_reserve (struct PostgresClosure *pg,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct TALER_ReserveEventP rep = {
- .header.size = htons (sizeof (rep)),
- .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
- .reserve_pub = *reserve_pub
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Notifying on reserve!\n");
- TEH_PG_event_notify (pg,
- &rep.header,
- NULL,
- 0);
-}
-
-
-static enum GNUNET_DB_QueryStatus
-insert1 (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1],
- struct GNUNET_TIME_Timestamp expiry,
- struct GNUNET_TIME_Timestamp gc,
- struct TALER_PaytoHashP h_payto,
- char *const *notify_s,
- struct GNUNET_TIME_Timestamp reserve_expiration,
- bool *transaction_duplicate,
- bool *conflict,
- uint64_t *reserve_uuid,
- enum GNUNET_DB_QueryStatus results[1])
-{
- enum GNUNET_DB_QueryStatus qs;
- PREPARE (pg,
- "batch1_reserve_create",
- "SELECT "
- " out_reserve_found AS conflicted"
- ",transaction_duplicate"
- ",ruuid AS reserve_uuid"
- " FROM exchange_do_batch_reserves_in_insert"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);");
-
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
- GNUNET_PQ_query_param_timestamp (&expiry),
- GNUNET_PQ_query_param_timestamp (&gc),
- GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference),
- TALER_PQ_query_param_amount (reserves[0].balance),
- GNUNET_PQ_query_param_string (reserves[0].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
- GNUNET_PQ_query_param_string (notify_s[0]),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("conflicted",
- &conflict[0]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate",
- &transaction_duplicate[0]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
- &reserve_uuid[0]),
- GNUNET_PQ_result_spec_end
- };
-
- TALER_payto_hash (reserves[0].sender_account_details,
- &h_payto);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "batch1_reserve_create",
- params,
- rs);
- if (qs < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserves 1(%d)\n",
- qs);
- results[0] = qs;
- return qs;
- }
- GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
- if ((! conflict[0]) && transaction_duplicate[0])
- {
- GNUNET_break (0);
- TEH_PG_rollback (pg);
- results[0] = GNUNET_DB_STATUS_HARD_ERROR;
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- return qs;
-}
-
-
-static enum GNUNET_DB_QueryStatus
-insert2 (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2],
- struct GNUNET_TIME_Timestamp expiry,
- struct GNUNET_TIME_Timestamp gc,
- struct TALER_PaytoHashP h_payto,
- char *const*notify_s,
- struct GNUNET_TIME_Timestamp reserve_expiration,
- bool *transaction_duplicate,
- bool *conflict,
- uint64_t *reserve_uuid,
- enum GNUNET_DB_QueryStatus results[1])
-{
- enum GNUNET_DB_QueryStatus qs1;
- PREPARE (pg,
- "batch2_reserve_create",
- "SELECT "
- "out_reserve_found AS conflicted"
- ",out_reserve_found2 AS conflicted2"
- ",transaction_duplicate"
- ",transaction_duplicate2"
- ",ruuid AS reserve_uuid"
- ",ruuid2 AS reserve_uuid2"
- " FROM exchange_do_batch2_reserves_insert"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);");
-
- struct GNUNET_PQ_QueryParam params[] = {
-
- GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
- GNUNET_PQ_query_param_timestamp (&expiry),
- GNUNET_PQ_query_param_timestamp (&gc),
- GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference),
- TALER_PQ_query_param_amount (reserves[0].balance),
- GNUNET_PQ_query_param_string (reserves[0].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
- GNUNET_PQ_query_param_string (notify_s[0]),
- GNUNET_PQ_query_param_string (notify_s[1]),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference),
- TALER_PQ_query_param_amount (reserves[1].balance),
- GNUNET_PQ_query_param_string (reserves[1].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("conflicted",
- &conflict[0]),
- GNUNET_PQ_result_spec_bool ("conflicted2",
- &conflict[1]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate",
- &transaction_duplicate[0]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate2",
- &transaction_duplicate[1]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
- &reserve_uuid[0]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid2",
- &reserve_uuid[1]),
- GNUNET_PQ_result_spec_end
- };
-
- TALER_payto_hash (reserves[0].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[1].sender_account_details,
- &h_payto);
-
-
- qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "batch2_reserve_create",
- params,
- rs);
- if (qs1 < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserves 2(%d)\n",
- qs1);
- results[0] = qs1;
- return qs1;
- }
-
- GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1);
- /* results[i] = (transaction_duplicate)
- ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
-
- if (
- ((! conflict[0]) && (transaction_duplicate[0]))
- || ((! conflict[1]) && (transaction_duplicate[1]))
- )
- {
- GNUNET_break (0);
- TEH_PG_rollback (pg); // ROLLBACK
- results[0] = GNUNET_DB_STATUS_HARD_ERROR;
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- return qs1;
-}
-
-
-static enum GNUNET_DB_QueryStatus
-insert4 (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4],
- struct GNUNET_TIME_Timestamp expiry,
- struct GNUNET_TIME_Timestamp gc,
- struct TALER_PaytoHashP h_payto,
- char *const*notify_s,
- struct GNUNET_TIME_Timestamp reserve_expiration,
- bool *transaction_duplicate,
- bool *conflict,
- uint64_t *reserve_uuid,
- enum GNUNET_DB_QueryStatus results[1])
+/**
+ * Closure for our helper_cb()
+ */
+struct Context
{
- enum GNUNET_DB_QueryStatus qs3;
- PREPARE (pg,
- "batch4_reserve_create",
- "SELECT "
- "out_reserve_found AS conflicted"
- ",out_reserve_found2 AS conflicted2"
- ",out_reserve_found3 AS conflicted3"
- ",out_reserve_found4 AS conflicted4"
- ",transaction_duplicate"
- ",transaction_duplicate2"
- ",transaction_duplicate3"
- ",transaction_duplicate4"
- ",ruuid AS reserve_uuid"
- ",ruuid2 AS reserve_uuid2"
- ",ruuid3 AS reserve_uuid3"
- ",ruuid4 AS reserve_uuid4"
- " FROM exchange_do_batch4_reserves_insert"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);");
+ /**
+ * Array of reserve UUIDs to initialize.
+ */
+ uint64_t *reserve_uuids;
+
+ /**
+ * Array with entries set to 'true' for duplicate transactions.
+ */
+ bool *transaction_duplicates;
+
+ /**
+ * Array with entries set to 'true' for rows with conflicts.
+ */
+ bool *conflicts;
+
+ /**
+ * Set to #GNUNET_SYSERR on failures.
+ */
+ enum GNUNET_GenericReturnValue status;
+
+ /**
+ * Single value (no array) set to true if we need
+ * to follow-up with an update.
+ */
+ bool needs_update;
+};
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
- GNUNET_PQ_query_param_timestamp (&expiry),
- GNUNET_PQ_query_param_timestamp (&gc),
- GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference),
- TALER_PQ_query_param_amount (reserves[0].balance),
- GNUNET_PQ_query_param_string (reserves[0].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
- GNUNET_PQ_query_param_string (notify_s[0]),
- GNUNET_PQ_query_param_string (notify_s[1]),
- GNUNET_PQ_query_param_string (notify_s[2]),
- GNUNET_PQ_query_param_string (notify_s[3]),
- GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference),
- TALER_PQ_query_param_amount (reserves[1].balance),
- GNUNET_PQ_query_param_string (reserves[1].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference),
- TALER_PQ_query_param_amount (reserves[2].balance),
- GNUNET_PQ_query_param_string (reserves[2].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[2].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference),
- TALER_PQ_query_param_amount (reserves[3].balance),
- GNUNET_PQ_query_param_string (reserves[3].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[3].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_end
- };
-
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("conflicted",
- &conflict[0]),
- GNUNET_PQ_result_spec_bool ("conflicted2",
- &conflict[1]),
- GNUNET_PQ_result_spec_bool ("conflicted3",
- &conflict[2]),
- GNUNET_PQ_result_spec_bool ("conflicted4",
- &conflict[3]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate",
- &transaction_duplicate[0]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate2",
- &transaction_duplicate[1]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate3",
- &transaction_duplicate[2]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate4",
- &transaction_duplicate[3]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
- &reserve_uuid[0]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid2",
- &reserve_uuid[1]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid3",
- &reserve_uuid[2]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid4",
- &reserve_uuid[3]),
- GNUNET_PQ_result_spec_end
- };
-
- TALER_payto_hash (reserves[0].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[1].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[2].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[3].sender_account_details,
- &h_payto);
-
- qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "batch4_reserve_create",
- params,
- rs);
- if (qs3 < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserves4 (%d)\n",
- qs3);
- results[0] = qs3;
- return qs3;
- }
-
- GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3);
-
- if (
- ((! conflict[0]) && (transaction_duplicate[0]))
- || ((! conflict[1]) && (transaction_duplicate[1]))
- || ((! conflict[2]) && (transaction_duplicate[2]))
- || ((! conflict[3]) && (transaction_duplicate[3]))
- )
- {
- GNUNET_break (0);
- TEH_PG_rollback (pg);
- results[0] = GNUNET_DB_STATUS_HARD_ERROR;
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- return qs3;
-}
-
-
-static enum GNUNET_DB_QueryStatus
-insert8 (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8],
- struct GNUNET_TIME_Timestamp expiry,
- struct GNUNET_TIME_Timestamp gc,
- struct TALER_PaytoHashP h_payto,
- char *const*notify_s,
- struct GNUNET_TIME_Timestamp reserve_expiration,
- bool *transaction_duplicate,
- bool *conflict,
- uint64_t *reserve_uuid,
- enum GNUNET_DB_QueryStatus results[1])
+/**
+ * Helper function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct Context *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+helper_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- enum GNUNET_DB_QueryStatus qs3;
- PREPARE (pg,
- "batch8_reserve_create",
- "SELECT "
- "out_reserve_found AS conflicted"
- ",out_reserve_found2 AS conflicted2"
- ",out_reserve_found3 AS conflicted3"
- ",out_reserve_found4 AS conflicted4"
- ",out_reserve_found5 AS conflicted5"
- ",out_reserve_found6 AS conflicted6"
- ",out_reserve_found7 AS conflicted7"
- ",out_reserve_found8 AS conflicted8"
- ",transaction_duplicate"
- ",transaction_duplicate2"
- ",transaction_duplicate3"
- ",transaction_duplicate4"
- ",transaction_duplicate5"
- ",transaction_duplicate6"
- ",transaction_duplicate7"
- ",transaction_duplicate8"
- ",ruuid AS reserve_uuid"
- ",ruuid2 AS reserve_uuid2"
- ",ruuid3 AS reserve_uuid3"
- ",ruuid4 AS reserve_uuid4"
- ",ruuid5 AS reserve_uuid5"
- ",ruuid6 AS reserve_uuid6"
- ",ruuid7 AS reserve_uuid7"
- ",ruuid8 AS reserve_uuid8"
- " FROM exchange_do_batch8_reserves_insert"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);");
-
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
- GNUNET_PQ_query_param_timestamp (&expiry),
- GNUNET_PQ_query_param_timestamp (&gc),
- GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference),
- TALER_PQ_query_param_amount (reserves[0].balance),
- GNUNET_PQ_query_param_string (reserves[0].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
- GNUNET_PQ_query_param_string (notify_s[0]),
- GNUNET_PQ_query_param_string (notify_s[1]),
- GNUNET_PQ_query_param_string (notify_s[2]),
- GNUNET_PQ_query_param_string (notify_s[3]),
- GNUNET_PQ_query_param_string (notify_s[4]),
- GNUNET_PQ_query_param_string (notify_s[5]),
- GNUNET_PQ_query_param_string (notify_s[6]),
- GNUNET_PQ_query_param_string (notify_s[7]),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference),
- TALER_PQ_query_param_amount (reserves[1].balance),
- GNUNET_PQ_query_param_string (reserves[1].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference),
- TALER_PQ_query_param_amount (reserves[2].balance),
- GNUNET_PQ_query_param_string (reserves[2].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[2].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference),
- TALER_PQ_query_param_amount (reserves[3].balance),
- GNUNET_PQ_query_param_string (reserves[3].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[3].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference),
- TALER_PQ_query_param_amount (reserves[4].balance),
- GNUNET_PQ_query_param_string (reserves[4].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[4].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference),
- TALER_PQ_query_param_amount (reserves[5].balance),
- GNUNET_PQ_query_param_string (reserves[5].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[5].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference),
- TALER_PQ_query_param_amount (reserves[6].balance),
- GNUNET_PQ_query_param_string (reserves[6].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[6].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-
- GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub),
- GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference),
- TALER_PQ_query_param_amount (reserves[7].balance),
- GNUNET_PQ_query_param_string (reserves[7].exchange_account_name),
- GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
- GNUNET_PQ_query_param_string (reserves[7].sender_account_details),
- GNUNET_PQ_query_param_timestamp (&reserve_expiration),
+ struct Context *ctx = cls;
- GNUNET_PQ_query_param_end
- };
-
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_bool ("conflicted",
- &conflict[0]),
- GNUNET_PQ_result_spec_bool ("conflicted2",
- &conflict[1]),
- GNUNET_PQ_result_spec_bool ("conflicted3",
- &conflict[2]),
- GNUNET_PQ_result_spec_bool ("conflicted4",
- &conflict[3]),
- GNUNET_PQ_result_spec_bool ("conflicted5",
- &conflict[4]),
- GNUNET_PQ_result_spec_bool ("conflicted6",
- &conflict[5]),
- GNUNET_PQ_result_spec_bool ("conflicted7",
- &conflict[6]),
- GNUNET_PQ_result_spec_bool ("conflicted8",
- &conflict[7]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate",
- &transaction_duplicate[0]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate2",
- &transaction_duplicate[1]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate3",
- &transaction_duplicate[2]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate4",
- &transaction_duplicate[3]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate5",
- &transaction_duplicate[4]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate6",
- &transaction_duplicate[5]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate7",
- &transaction_duplicate[6]),
- GNUNET_PQ_result_spec_bool ("transaction_duplicate8",
- &transaction_duplicate[7]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
- &reserve_uuid[0]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid2",
- &reserve_uuid[1]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid3",
- &reserve_uuid[2]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid4",
- &reserve_uuid[3]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid5",
- &reserve_uuid[4]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid6",
- &reserve_uuid[5]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid7",
- &reserve_uuid[6]),
- GNUNET_PQ_result_spec_uint64 ("reserve_uuid8",
- &reserve_uuid[7]),
- GNUNET_PQ_result_spec_end
- };
-
- TALER_payto_hash (reserves[0].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[1].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[2].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[3].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[4].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[5].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[6].sender_account_details,
- &h_payto);
- TALER_payto_hash (reserves[7].sender_account_details,
- &h_payto);
-
- qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "batch8_reserve_create",
- params,
- rs);
- if (qs3 < 0)
+ for (unsigned int i = 0; i<num_results; i++)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserves8 (%d)\n",
- qs3);
- results[0] = qs3;
- return qs3;
- }
-
- GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3);
- /* results[i] = (transaction_duplicate)
- ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool (
+ "transaction_duplicate",
+ &ctx->transaction_duplicates[i]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint64 ("ruuid",
+ &ctx->reserve_uuids[i]),
+ &ctx->conflicts[i]),
+ GNUNET_PQ_result_spec_end
+ };
- if (
- ((! conflict[0]) && (transaction_duplicate[0]))
- || ((! conflict[1]) && (transaction_duplicate[1]))
- || ((! conflict[2]) && (transaction_duplicate[2]))
- || ((! conflict[3]) && (transaction_duplicate[3]))
- || ((! conflict[4]) && (transaction_duplicate[4]))
- || ((! conflict[5]) && (transaction_duplicate[5]))
- || ((! conflict[6]) && (transaction_duplicate[6]))
- || ((! conflict[7]) && (transaction_duplicate[7]))
- )
- {
- GNUNET_break (0);
- TEH_PG_rollback (pg);
- results[0] = GNUNET_DB_STATUS_HARD_ERROR;
- return GNUNET_DB_STATUS_HARD_ERROR;
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->status = GNUNET_SYSERR;
+ return;
+ }
+ if (! ctx->transaction_duplicates[i])
+ ctx->needs_update |= ctx->conflicts[i];
}
- results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- return qs3;
}
enum GNUNET_DB_QueryStatus
-TEH_PG_reserves_in_insert (void *cls,
- const struct
- TALER_EXCHANGEDB_ReserveInInfo *reserves,
- unsigned int reserves_length,
- unsigned int batch_size,
- enum GNUNET_DB_QueryStatus *results)
+TEH_PG_reserves_in_insert (
+ void *cls,
+ const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
+ unsigned int reserves_length,
+ enum GNUNET_DB_QueryStatus *results)
{
struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs1;
- enum GNUNET_DB_QueryStatus qs2;
- enum GNUNET_DB_QueryStatus qs4;
- enum GNUNET_DB_QueryStatus qs5;
- struct GNUNET_TIME_Timestamp expiry;
- struct GNUNET_TIME_Timestamp gc;
- struct TALER_PaytoHashP h_payto;
- uint64_t reserve_uuid[reserves_length];
- bool transaction_duplicate[reserves_length];
- bool need_update = false;
- bool t_duplicate = false;
+ unsigned int dups = 0;
+
+ struct TALER_PaytoHashP h_paytos[GNUNET_NZL (reserves_length)];
+ char *notify_s[GNUNET_NZL (reserves_length)];
+ struct TALER_ReservePublicKeyP reserve_pubs[GNUNET_NZL (reserves_length)];
+ struct TALER_Amount balances[GNUNET_NZL (reserves_length)];
+ struct GNUNET_TIME_Timestamp execution_times[GNUNET_NZL (reserves_length)];
+ const char *sender_account_details[GNUNET_NZL (reserves_length)];
+ const char *exchange_account_names[GNUNET_NZL (reserves_length)];
+ uint64_t wire_references[GNUNET_NZL (reserves_length)];
+ uint64_t reserve_uuids[GNUNET_NZL (reserves_length)];
+ bool transaction_duplicates[GNUNET_NZL (reserves_length)];
+ bool conflicts[GNUNET_NZL (reserves_length)];
struct GNUNET_TIME_Timestamp reserve_expiration
= GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
- bool conflicts[reserves_length];
- char *notify_s[reserves_length];
+ struct GNUNET_TIME_Timestamp gc
+ = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time);
+ enum GNUNET_DB_QueryStatus qs;
+ bool need_update;
+
+ for (unsigned int i = 0; i<reserves_length; i++)
+ {
+ const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
+
+ TALER_payto_hash (reserve->sender_account_details,
+ &h_paytos[i]);
+ notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);
+ reserve_pubs[i] = *reserve->reserve_pub;
+ balances[i] = *reserve->balance;
+ execution_times[i] = reserve->execution_time;
+ sender_account_details[i] = reserve->sender_account_details;
+ exchange_account_names[i] = reserve->exchange_account_name;
+ wire_references[i] = reserve->wire_reference;
+ }
+ /* NOTE: kind-of pointless to explicitly start a transaction here... */
if (GNUNET_OK !=
TEH_PG_preflight (pg))
{
GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
+ qs = GNUNET_DB_STATUS_HARD_ERROR;
+ goto finished;
}
-
- expiry = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,
- pg->idle_reserve_expiration_time));
- gc = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
- pg->legal_reserve_expiration_time));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Creating reserve %s with expiration in %s\n",
- TALER_B2S (&(reserves->reserve_pub)),
- GNUNET_STRINGS_relative_time_to_string (
- pg->idle_reserve_expiration_time,
- GNUNET_NO));
-
if (GNUNET_OK !=
TEH_PG_start_read_committed (pg,
"READ_COMMITED"))
{
GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
+ qs = GNUNET_DB_STATUS_HARD_ERROR;
+ goto finished;
}
-
- /* Optimistically assume this is a 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 needs the reserve entry as a foreign key. */
- for (unsigned int i = 0; i<reserves_length; i++)
- {
- const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
-
- notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);
- }
-
- unsigned int i = 0;
-
- while (i < reserves_length)
+ PREPARE (pg,
+ "reserves_insert_with_array",
+ "SELECT"
+ " transaction_duplicate"
+ ",ruuid"
+ " FROM exchange_do_array_reserves_insert"
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
{
- unsigned int bs = GNUNET_MIN (batch_size,
- reserves_length - i);
- bs = 1; // FIXME-JOSEPH: for now, until pg_notify is gone!
- if (bs >= 8)
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_timestamp (&gc),
+ GNUNET_PQ_query_param_timestamp (&reserve_expiration),
+ GNUNET_PQ_query_param_array_auto_from_type (reserves_length,
+ reserve_pubs,
+ pg->conn),
+ GNUNET_PQ_query_param_array_uint64 (reserves_length,
+ wire_references,
+ pg->conn),
+ TALER_PQ_query_param_array_amount (
+ reserves_length,
+ balances,
+ pg->conn),
+ GNUNET_PQ_query_param_array_ptrs_string (
+ reserves_length,
+ (const char **) exchange_account_names,
+ pg->conn),
+ GNUNET_PQ_query_param_array_timestamp (
+ reserves_length,
+ execution_times,
+ pg->conn),
+ GNUNET_PQ_query_param_array_auto_from_type (
+ reserves_length,
+ h_paytos,
+ pg->conn),
+ GNUNET_PQ_query_param_array_ptrs_string (
+ reserves_length,
+ (const char **) sender_account_details,
+ pg->conn),
+ GNUNET_PQ_query_param_array_ptrs_string (
+ reserves_length,
+ (const char **) notify_s,
+ pg->conn),
+ GNUNET_PQ_query_param_end
+ };
+ struct Context ctx = {
+ .reserve_uuids = reserve_uuids,
+ .transaction_duplicates = transaction_duplicates,
+ .conflicts = conflicts,
+ .needs_update = false,
+ .status = GNUNET_OK
+ };
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "reserves_insert_with_array",
+ params,
+ &helper_cb,
+ &ctx);
+ GNUNET_PQ_cleanup_query_params_closures (params);
+ if ( (qs < 0) ||
+ (GNUNET_OK != ctx.status) )
{
- qs1 = insert8 (pg,
- &reserves[i],
- expiry,
- gc,
- h_payto,
- &notify_s[i],
- reserve_expiration,
- &transaction_duplicate[i],
- &conflicts[i],
- &reserve_uuid[i],
- &results[i]);
-
- if (qs1<0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserve batch_8 (%d)\n",
- qs1);
- return qs1;
- }
- need_update |= conflicts[i];
- need_update |= conflicts[i + 1];
- need_update |= conflicts[i + 2];
- need_update |= conflicts[i + 3];
- need_update |= conflicts[i + 4];
- need_update |= conflicts[i + 5];
- need_update |= conflicts[i + 6];
- need_update |= conflicts[i + 7];
- t_duplicate |= transaction_duplicate[i];
- t_duplicate |= transaction_duplicate[i + 1];
- t_duplicate |= transaction_duplicate[i + 2];
- t_duplicate |= transaction_duplicate[i + 3];
- t_duplicate |= transaction_duplicate[i + 4];
- t_duplicate |= transaction_duplicate[i + 5];
- t_duplicate |= transaction_duplicate[i + 6];
- t_duplicate |= transaction_duplicate[i + 7];
- i += 8;
- continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to insert into reserves (%d)\n",
+ qs);
+ goto finished;
}
- switch (bs)
- {
- case 7:
- case 6:
- case 5:
- case 4:
- qs4 = insert4 (pg,
- &reserves[i],
- expiry,
- gc,
- h_payto,
- &notify_s[i],
- reserve_expiration,
- &transaction_duplicate[i],
- &conflicts[i],
- &reserve_uuid[i],
- &results[i]);
+ need_update = ctx.needs_update;
+ }
- if (qs4<0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserve batch_4 (%d)\n",
- qs4);
- return qs4;
- }
- need_update |= conflicts[i];
- need_update |= conflicts[i + 1];
- need_update |= conflicts[i + 2];
- need_update |= conflicts[i + 3];
- t_duplicate |= transaction_duplicate[i];
- t_duplicate |= transaction_duplicate[i + 1];
- t_duplicate |= transaction_duplicate[i + 2];
- t_duplicate |= transaction_duplicate[i + 3];
- // fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]);
- i += 4;
- break;
- case 3:
- case 2:
- qs5 = insert2 (pg,
- &reserves[i],
- expiry,
- gc,
- h_payto,
- &notify_s[i],
- reserve_expiration,
- &transaction_duplicate[i],
- &conflicts[i],
- &reserve_uuid[i],
- &results[i]);
- if (qs5<0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserve batch_2 (%d)\n",
- qs5);
- return qs5;
- }
- need_update |= conflicts[i];
- need_update |= conflicts[i + 1];
- t_duplicate |= transaction_duplicate[i];
- t_duplicate |= transaction_duplicate[i + 1];
- results[i] = (t_duplicate)
- ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- // fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]);
- i += 2;
- break;
- case 1:
- qs2 = insert1 (pg,
- &reserves[i],
- expiry,
- gc,
- h_payto,
- &notify_s[i],
- reserve_expiration,
- &transaction_duplicate[i],
- &conflicts[i],
- &reserve_uuid[i],
- &results[i]);
- if (qs2<0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to create reserve batch_1 (%d)\n)"
- ,qs2);
- return qs2;
- }
- need_update |= conflicts[i];
- t_duplicate |= transaction_duplicate[i];
- // fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]);
- i += 1;
- break;
- case 0:
- GNUNET_assert (0);
- break;
- }
- } /* end while */
- // commit
{
enum GNUNET_DB_QueryStatus cs;
@@ -853,44 +266,59 @@ TEH_PG_reserves_in_insert (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to commit\n");
- return cs;
+ qs = cs;
+ goto finished;
}
}
- if (! need_update)
+
+ for (unsigned int i = 0; i<reserves_length; i++)
{
- goto exit;
+ if (transaction_duplicates[i])
+ dups++;
+ results[i] = transaction_duplicates[i]
+ ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
- // begin serializable
+
+ if (! need_update)
{
- if (GNUNET_OK !=
- TEH_PG_start (pg,
- "reserve-insert-continued"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
+ qs = reserves_length;
+ goto finished;
}
-
- enum GNUNET_DB_QueryStatus qs3;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Reserve update needed for some reserves in the batch\n");
PREPARE (pg,
"reserves_update",
"SELECT"
" out_duplicate AS duplicate "
"FROM exchange_do_batch_reserves_update"
- " ($1,$2,$3,$4,$5,$6,$7,$8);");
+ " ($1,$2,$3,$4,$5,$6,$7);");
+
+ if (GNUNET_OK !=
+ TEH_PG_start (pg,
+ "reserve-insert-continued"))
+ {
+ GNUNET_break (0);
+ qs = GNUNET_DB_STATUS_HARD_ERROR;
+ goto finished;
+ }
+
for (unsigned int i = 0; i<reserves_length; i++)
{
+ if (transaction_duplicates[i])
+ continue;
if (! conflicts[i])
continue;
{
bool duplicate;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub),
- GNUNET_PQ_query_param_timestamp (&expiry),
- GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference),
- TALER_PQ_query_param_amount (reserves[i].balance),
- GNUNET_PQ_query_param_string (reserves[i].exchange_account_name),
- GNUNET_PQ_query_param_auto_from_type (&h_payto),
+ GNUNET_PQ_query_param_auto_from_type (&reserve_pubs[i]),
+ GNUNET_PQ_query_param_timestamp (&reserve_expiration),
+ GNUNET_PQ_query_param_uint64 (&wire_references[i]),
+ TALER_PQ_query_param_amount (pg->conn,
+ &balances[i]),
+ GNUNET_PQ_query_param_string (exchange_account_names[i]),
+ GNUNET_PQ_query_param_auto_from_type (&h_paytos[i]),
GNUNET_PQ_query_param_string (notify_s[i]),
GNUNET_PQ_query_param_end
};
@@ -899,35 +327,47 @@ TEH_PG_reserves_in_insert (void *cls,
&duplicate),
GNUNET_PQ_result_spec_end
};
- qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "reserves_update",
- params,
- rs);
- if (qs3<0)
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "reserves_update",
+ params,
+ rs);
+ if (qs < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to update reserves (%d)\n",
- qs3);
- results[i] = qs3;
- return qs3;
+ qs);
+ results[i] = qs;
+ goto finished;
}
results[i] = duplicate
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
}
}
-
{
enum GNUNET_DB_QueryStatus cs;
cs = TEH_PG_commit (pg);
if (cs < 0)
- return cs;
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to commit\n");
+ qs = cs;
+ goto finished;
+ }
}
-
-exit:
+finished:
for (unsigned int i = 0; i<reserves_length; i++)
GNUNET_free (notify_s[i]);
-
- return reserves_length;
+ if (qs < 0)
+ return qs;
+ GNUNET_PQ_event_do_poll (pg->conn);
+ if (0 != dups)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "%u/%u duplicates among incoming transactions. Try increasing WIREWATCH_IDLE_SLEEP_INTERVAL in the [exchange] configuration section (if this happens a lot).\n",
+ dups,
+ reserves_length);
+ return qs;
}
diff --git a/src/exchangedb/pg_reserves_in_insert.h b/src/exchangedb/pg_reserves_in_insert.h
index f92843e79..938df3adb 100644
--- a/src/exchangedb/pg_reserves_in_insert.h
+++ b/src/exchangedb/pg_reserves_in_insert.h
@@ -33,7 +33,6 @@
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @param reserves array of reserves to insert
* @param reserves_length length of the @a reserves array
- * @param batch_size how many inserts to do in one go
* @param[out] results set to query status per reserve, must be of length @a reserves_length
* @return transaction status code
*/
@@ -42,7 +41,6 @@ TEH_PG_reserves_in_insert (
void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
- unsigned int batch_size,
enum GNUNET_DB_QueryStatus *results);
diff --git a/src/exchangedb/pg_reserves_update.c b/src/exchangedb/pg_reserves_update.c
index 4a8861020..bfd32c6ce 100644
--- a/src/exchangedb/pg_reserves_update.c
+++ b/src/exchangedb/pg_reserves_update.c
@@ -27,13 +27,14 @@
enum GNUNET_DB_QueryStatus
TEH_PG_reserves_update (void *cls,
- const struct TALER_EXCHANGEDB_Reserve *reserve)
+ const struct TALER_EXCHANGEDB_Reserve *reserve)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_timestamp (&reserve->expiry),
GNUNET_PQ_query_param_timestamp (&reserve->gc),
- TALER_PQ_query_param_amount (&reserve->balance),
+ TALER_PQ_query_param_amount (pg->conn,
+ &reserve->balance),
GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
GNUNET_PQ_query_param_end
};
@@ -44,9 +45,8 @@ TEH_PG_reserves_update (void *cls,
" SET"
" expiration_date=$1"
",gc_date=$2"
- ",current_balance_val=$3"
- ",current_balance_frac=$4"
- " WHERE reserve_pub=$5;");
+ ",current_balance=$3"
+ " WHERE reserve_pub=$4;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"reserve_update",
params);
diff --git a/src/exchangedb/pg_rollback.c b/src/exchangedb/pg_rollback.c
index 6b200b55d..3610487f3 100644
--- a/src/exchangedb/pg_rollback.c
+++ b/src/exchangedb/pg_rollback.c
@@ -48,5 +48,3 @@ TEH_PG_rollback (void *cls)
es));
pg->transaction_name = NULL;
}
-
-
diff --git a/src/exchangedb/pg_select_account_merges_above_serial_id.c b/src/exchangedb/pg_select_account_merges_above_serial_id.c
index 95c2f93a1..6c3c81121 100644
--- a/src/exchangedb/pg_select_account_merges_above_serial_id.c
+++ b/src/exchangedb/pg_select_account_merges_above_serial_id.c
@@ -168,12 +168,10 @@ TEH_PG_select_account_merges_above_serial_id (
",am.purse_pub"
",pr.h_contract_terms"
",pr.purse_expiration"
- ",pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
+ ",pr.amount_with_fee"
",pr.age_limit"
",pr.flags"
- ",pr.purse_fee_val"
- ",pr.purse_fee_frac"
+ ",pr.purse_fee"
",pm.merge_timestamp"
",am.reserve_sig"
" FROM account_merges am"
diff --git a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
index abddab52f..0d5d0ee25 100644
--- a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
+++ b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
@@ -26,8 +26,6 @@
#include "pg_helper.h"
-
-
/**
* Closure for #get_kyc_amounts_cb().
*/
@@ -112,7 +110,6 @@ get_kyc_amounts_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_aggregation_amounts_for_kyc_check (
void *cls,
@@ -138,8 +135,7 @@ TEH_PG_select_aggregation_amounts_for_kyc_check (
PREPARE (pg,
"select_kyc_relevant_aggregation_events",
"SELECT"
- " amount_val"
- ",amount_frac"
+ " amount"
",execution_date AS date"
" FROM wire_out"
" WHERE wire_target_h_payto=$1"
diff --git a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h
index 87fc8677a..b91740581 100644
--- a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h
+++ b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h
@@ -44,4 +44,5 @@ TEH_PG_select_aggregation_amounts_for_kyc_check (
struct GNUNET_TIME_Absolute time_limit,
TALER_EXCHANGEDB_KycAmountCallback kac,
void *kac_cls);
+
#endif
diff --git a/src/exchangedb/pg_select_aggregation_transient.c b/src/exchangedb/pg_select_aggregation_transient.c
index f3e39c532..f9b6193ed 100644
--- a/src/exchangedb/pg_select_aggregation_transient.c
+++ b/src/exchangedb/pg_select_aggregation_transient.c
@@ -49,12 +49,11 @@ TEH_PG_select_aggregation_transient (
wtid),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_select_aggregation_transient() */
+ /* Used in #postgres_select_aggregation_transient() */
PREPARE (pg,
"select_aggregation_transient",
"SELECT"
- " amount_val"
- " ,amount_frac"
+ " amount"
" ,wtid_raw"
" FROM aggregation_transient"
" WHERE wire_target_h_payto=$1"
diff --git a/src/exchangedb/pg_select_aggregations_above_serial.c b/src/exchangedb/pg_select_aggregations_above_serial.c
new file mode 100644
index 000000000..52d202702
--- /dev/null
+++ b/src/exchangedb/pg_select_aggregations_above_serial.c
@@ -0,0 +1,137 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_aggregations_above_serial.c
+ * @brief Implementation of the select_aggregations_above_serial function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_aggregations_above_serial.h"
+#include "pg_helper.h"
+
+/**
+ * Closure for #aggregation_serial_helper_cb().
+ */
+struct AggregationSerialContext
+{
+
+ /**
+ * Callback to call.
+ */
+ TALER_EXCHANGEDB_AggregationCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Status code, set to #GNUNET_SYSERR on hard errors.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Helper function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct AggregationSerialContext`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+aggregation_serial_helper_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct AggregationSerialContext *dsc = cls;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ uint64_t tracking_rowid;
+ uint64_t batch_deposit_serial_id;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id",
+ &tracking_rowid),
+ GNUNET_PQ_result_spec_uint64 ("batch_deposit_serial_id",
+ &batch_deposit_serial_id),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ dsc->status = GNUNET_SYSERR;
+ return;
+ }
+ dsc->cb (dsc->cb_cls,
+ tracking_rowid,
+ batch_deposit_serial_id);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aggregations_above_serial (
+ void *cls,
+ uint64_t min_tracking_serial_id,
+ TALER_EXCHANGEDB_AggregationCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&min_tracking_serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct AggregationSerialContext asc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ /* Fetch aggregations with rowid '\geq' the given parameter */
+ PREPARE (pg,
+ "select_aggregations_above_serial",
+ "SELECT"
+ " aggregation_serial_id"
+ ",batch_deposit_serial_id"
+ " FROM aggregation_tracking"
+ " WHERE aggregation_serial_id>=$1"
+ " ORDER BY aggregation_serial_id ASC;");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "select_aggregations_above_serial",
+ params,
+ &aggregation_serial_helper_cb,
+ &asc);
+ if (GNUNET_OK != asc.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_aggregations_above_serial.h b/src/exchangedb/pg_select_aggregations_above_serial.h
new file mode 100644
index 000000000..2883b19f2
--- /dev/null
+++ b/src/exchangedb/pg_select_aggregations_above_serial.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_aggregations_above_serial.h
+ * @brief implementation of the select_aggregations_above_serial function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_AGGREGATIONS_ABOVE_SERIAL_H
+#define PG_SELECT_AGGREGATIONS_ABOVE_SERIAL_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Select all aggregation tracking IDs in the database
+ * above a given @a min_tracking_serial_id.
+ *
+ * @param cls closure
+ * @param min_tracking_serial_id only return entries strictly above this row (and in order)
+ * @param cb function to call on all such aggregations
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aggregations_above_serial (
+ void *cls,
+ uint64_t min_tracking_serial_id,
+ TALER_EXCHANGEDB_AggregationCallback cb,
+ void *cb_cls);
+
+
+#endif
diff --git a/src/exchangedb/pg_select_aml_history.c b/src/exchangedb/pg_select_aml_history.c
index c54a3ef0c..0461e0d9b 100644
--- a/src/exchangedb/pg_select_aml_history.c
+++ b/src/exchangedb/pg_select_aml_history.c
@@ -138,8 +138,7 @@ TEH_PG_select_aml_history (
PREPARE (pg,
"lookup_aml_history",
"SELECT"
- " new_threshold_val"
- ",new_threshold_frac"
+ " new_threshold"
",new_status"
",decision_time"
",justification"
diff --git a/src/exchangedb/pg_select_aml_process.c b/src/exchangedb/pg_select_aml_process.c
index 5df5fe657..c34cae4bb 100644
--- a/src/exchangedb/pg_select_aml_process.c
+++ b/src/exchangedb/pg_select_aml_process.c
@@ -140,8 +140,7 @@ TEH_PG_select_aml_process (
"SELECT"
" aml_status_serial_id"
",h_payto"
- ",threshold_val"
- ",threshold_frac"
+ ",threshold"
",status"
" FROM aml_status"
" WHERE aml_status_serial_id > $2"
@@ -153,8 +152,7 @@ TEH_PG_select_aml_process (
"SELECT"
" aml_status_serial_id"
",h_payto"
- ",threshold_val"
- ",threshold_frac"
+ ",threshold"
",status"
" FROM aml_status"
" WHERE aml_status_serial_id < $2"
diff --git a/src/exchangedb/pg_select_aml_threshold.c b/src/exchangedb/pg_select_aml_threshold.c
new file mode 100644
index 000000000..23286f029
--- /dev/null
+++ b/src/exchangedb/pg_select_aml_threshold.c
@@ -0,0 +1,70 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_aml_threshold.c
+ * @brief Implementation of the select_aml_threshold function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_aml_threshold.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_threshold (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ enum TALER_AmlDecisionState *decision,
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ struct TALER_Amount *threshold)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (h_payto),
+ GNUNET_PQ_query_param_end
+ };
+ uint32_t status32 = TALER_AML_NORMAL;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("threshold",
+ threshold),
+ GNUNET_PQ_result_spec_uint32 ("status",
+ &status32),
+ GNUNET_PQ_result_spec_uint64 ("kyc_requirement",
+ &kyc->requirement_row),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "select_aml_threshold",
+ "SELECT"
+ " threshold"
+ ",status"
+ ",kyc_requirement"
+ " FROM aml_status"
+ " WHERE h_payto=$1;");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_aml_threshold",
+ params,
+ rs);
+ *decision = (enum TALER_AmlDecisionState) status32;
+ kyc->ok = (TALER_AML_FROZEN != *decision)
+ || (0 != kyc->requirement_row);
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_aml_threshold.h b/src/exchangedb/pg_select_aml_threshold.h
new file mode 100644
index 000000000..8f0e3bcfc
--- /dev/null
+++ b/src/exchangedb/pg_select_aml_threshold.h
@@ -0,0 +1,48 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_aml_threshold.h
+ * @brief implementation of the select_aml_threshold function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_AML_THRESHOLD_H
+#define PG_SELECT_AML_THRESHOLD_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Obtain the current AML threshold set for an account.
+ *
+ * @param cls closure
+ * @param h_payto account for which the AML threshold is stored
+ * @param[out] decision set to current AML decision
+ * @param[out] kyc set to KYC requirements imposed by AML, if any
+ * @param[out] threshold set to the existing threshold
+ * @return database transaction status, 0 if no threshold was set
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aml_threshold (
+ void *cls,
+ const struct TALER_PaytoHashP *h_payto,
+ enum TALER_AmlDecisionState *decision,
+ struct TALER_EXCHANGEDB_KycStatus *kyc,
+ struct TALER_Amount *threshold);
+
+
+#endif
diff --git a/src/exchangedb/pg_select_auditor_denom_sig.c b/src/exchangedb/pg_select_auditor_denom_sig.c
index 90e0c5096..1dd6bd3d1 100644
--- a/src/exchangedb/pg_select_auditor_denom_sig.c
+++ b/src/exchangedb/pg_select_auditor_denom_sig.c
@@ -64,4 +64,3 @@ TEH_PG_select_auditor_denom_sig (
params,
rs);
}
-
diff --git a/src/exchangedb/pg_select_batch_deposits_missing_wire.c b/src/exchangedb/pg_select_batch_deposits_missing_wire.c
new file mode 100644
index 000000000..8f966326a
--- /dev/null
+++ b/src/exchangedb/pg_select_batch_deposits_missing_wire.c
@@ -0,0 +1,144 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_batch_deposits_missing_wire.c
+ * @brief Implementation of the select_batch_deposits_missing_wire function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_batch_deposits_missing_wire.h"
+#include "pg_helper.h"
+
+/**
+ * Closure for #missing_wire_cb().
+ */
+struct MissingWireContext
+{
+ /**
+ * Function to call per result.
+ */
+ TALER_EXCHANGEDB_WireMissingCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Set to #GNUNET_SYSERR on error.
+ */
+ enum GNUNET_GenericReturnValue status;
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct MissingWireContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+missing_wire_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct MissingWireContext *mwc = cls;
+ struct PostgresClosure *pg = mwc->pg;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ uint64_t batch_deposit_serial_id;
+ struct GNUNET_TIME_Timestamp deadline;
+ struct TALER_PaytoHashP wire_target_h_payto;
+ struct TALER_Amount total_amount;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("batch_deposit_serial_id",
+ &batch_deposit_serial_id),
+ GNUNET_PQ_result_spec_auto_from_type ("wire_target_h_payto",
+ &wire_target_h_payto),
+ GNUNET_PQ_result_spec_timestamp ("deadline",
+ &deadline),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("total_amount",
+ &total_amount),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ mwc->status = GNUNET_SYSERR;
+ return;
+ }
+ mwc->cb (mwc->cb_cls,
+ batch_deposit_serial_id,
+ &total_amount,
+ &wire_target_h_payto,
+ deadline);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_batch_deposits_missing_wire (
+ void *cls,
+ uint64_t min_batch_deposit_serial_id,
+ TALER_EXCHANGEDB_WireMissingCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&min_batch_deposit_serial_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct MissingWireContext mwc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg,
+ .status = GNUNET_OK
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "deposits_get_deposits_missing_wire",
+ "SELECT"
+ " batch_deposit_serial_id"
+ ",wire_target_h_payto"
+ ",deadline"
+ ",total_amount"
+ " FROM exchange_do_select_deposits_missing_wire"
+ " ($1);");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "deposits_get_deposits_missing_wire",
+ params,
+ &missing_wire_cb,
+ &mwc);
+ if (GNUNET_OK != mwc.status)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.h b/src/exchangedb/pg_select_batch_deposits_missing_wire.h
index b16efdce1..16f1d0cb3 100644
--- a/src/exchangedb/pg_select_history_requests_above_serial_id.h
+++ b/src/exchangedb/pg_select_batch_deposits_missing_wire.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -14,31 +14,31 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_select_history_requests_above_serial_id.h
- * @brief implementation of the select_history_requests_above_serial_id function for Postgres
+ * @file exchangedb/pg_select_batch_deposits_missing_wire.h
+ * @brief implementation of the select_batch_deposits_missing_wire function for Postgres
* @author Christian Grothoff
*/
-#ifndef PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H
-#define PG_SELECT_HISTORY_REQUESTS_ABOVE_SERIAL_ID_H
+#ifndef PG_SELECT_DEPOSITS_MISSING_WIRE_H
+#define PG_SELECT_DEPOSITS_MISSING_WIRE_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
- * Select history requests above @a serial_id in monotonically increasing
- * order.
+ * Select all of those batch deposits in the database
+ * above the given serial ID.
*
* @param cls closure
- * @param serial_id highest serial ID to exclude (select strictly larger)
- * @param cb function to call on each result
+ * @param min_batch_deposit_serial_id select all batch deposits above this ID
+ * @param cb function to call on all such deposits
* @param cb_cls closure for @a cb
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_select_history_requests_above_serial_id (
+TEH_PG_select_batch_deposits_missing_wire (
void *cls,
- uint64_t serial_id,
- TALER_EXCHANGEDB_HistoryRequestCallback cb,
+ uint64_t min_batch_deposit_serial_id,
+ TALER_EXCHANGEDB_WireMissingCallback cb,
void *cb_cls);
#endif
diff --git a/src/exchangedb/pg_select_deposits_above_serial_id.c b/src/exchangedb/pg_select_coin_deposits_above_serial_id.c
index b3258bd4c..000b908ed 100644
--- a/src/exchangedb/pg_select_deposits_above_serial_id.c
+++ b/src/exchangedb/pg_select_coin_deposits_above_serial_id.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -14,21 +14,21 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_select_deposits_above_serial_id.c
- * @brief Implementation of the select_deposits_above_serial_id function for Postgres
+ * @file exchangedb/pg_select_coin_deposits_above_serial_id.c
+ * @brief Implementation of the select_coin_deposits_above_serial_id function for Postgres
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
-#include "pg_select_deposits_above_serial_id.h"
+#include "pg_select_coin_deposits_above_serial_id.h"
#include "pg_helper.h"
/**
* Closure for #deposit_serial_helper_cb().
*/
-struct DepositSerialContext
+struct CoinDepositSerialContext
{
/**
@@ -57,16 +57,16 @@ struct DepositSerialContext
* Helper function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls closure of type `struct DepositSerialContext`
+ * @param cls closure of type `struct CoinDepositSerialContext`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-deposit_serial_helper_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+coin_deposit_serial_helper_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct DepositSerialContext *dsc = cls;
+ struct CoinDepositSerialContext *dsc = cls;
struct PostgresClosure *pg = dsc->pg;
for (unsigned int i = 0; i<num_results; i++)
@@ -93,6 +93,10 @@ deposit_serial_helper_cb (void *cls,
GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
&deposit.coin.h_age_commitment),
&deposit.coin.no_age_commitment),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_auto_from_type ("wallet_data_hash",
+ &deposit.wallet_data_hash),
+ &deposit.no_wallet_data_hash),
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
&deposit.csig),
GNUNET_PQ_result_spec_timestamp ("refund_deadline",
@@ -107,7 +111,7 @@ deposit_serial_helper_cb (void *cls,
&deposit.receiver_wire_account),
GNUNET_PQ_result_spec_bool ("done",
&done),
- GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
+ GNUNET_PQ_result_spec_uint64 ("coin_deposit_serial_id",
&rowid),
GNUNET_PQ_result_spec_end
};
@@ -139,7 +143,7 @@ deposit_serial_helper_cb (void *cls,
enum GNUNET_DB_QueryStatus
-TEH_PG_select_deposits_above_serial_id (
+TEH_PG_select_coin_deposits_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_DepositCallback cb,
@@ -150,7 +154,7 @@ TEH_PG_select_deposits_above_serial_id (
GNUNET_PQ_query_param_uint64 (&serial_id),
GNUNET_PQ_query_param_end
};
- struct DepositSerialContext dsc = {
+ struct CoinDepositSerialContext dsc = {
.cb = cb,
.cb_cls = cb_cls,
.pg = pg,
@@ -160,37 +164,39 @@ TEH_PG_select_deposits_above_serial_id (
/* Fetch deposits with rowid '\geq' the given parameter */
PREPARE (pg,
- "audit_get_deposits_incr",
+ "audit_get_coin_deposits_incr",
"SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",wallet_timestamp"
- ",exchange_timestamp"
- ",merchant_pub"
+ " cdep.amount_with_fee"
+ ",bdep.wallet_timestamp"
+ ",bdep.exchange_timestamp"
+ ",bdep.merchant_pub"
+ ",bdep.wallet_data_hash"
",denom.denom_pub"
",kc.coin_pub"
",kc.age_commitment_hash"
- ",coin_sig"
- ",refund_deadline"
- ",wire_deadline"
- ",h_contract_terms"
- ",wire_salt"
- ",payto_uri AS receiver_wire_account"
- ",done"
- ",deposit_serial_id"
- " FROM deposits"
- " JOIN wire_targets USING (wire_target_h_payto)"
- " JOIN known_coins kc USING (coin_pub)"
- " JOIN denominations denom USING (denominations_serial)"
- " WHERE ("
- " (deposit_serial_id>=$1)"
- " )"
- " ORDER BY deposit_serial_id ASC;");
-
+ ",cdep.coin_sig"
+ ",bdep.refund_deadline"
+ ",bdep.wire_deadline"
+ ",bdep.h_contract_terms"
+ ",bdep.wire_salt"
+ ",wt.payto_uri AS receiver_wire_account"
+ ",bdep.done"
+ ",cdep.coin_deposit_serial_id"
+ " FROM coin_deposits cdep"
+ " JOIN batch_deposits bdep"
+ " USING (batch_deposit_serial_id)"
+ " JOIN wire_targets wt"
+ " USING (wire_target_h_payto)"
+ " JOIN known_coins kc"
+ " USING (coin_pub)"
+ " JOIN denominations denom"
+ " USING (denominations_serial)"
+ " WHERE (coin_deposit_serial_id>=$1)"
+ " ORDER BY coin_deposit_serial_id ASC;");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "audit_get_deposits_incr",
+ "audit_get_coin_deposits_incr",
params,
- &deposit_serial_helper_cb,
+ &coin_deposit_serial_helper_cb,
&dsc);
if (GNUNET_OK != dsc.status)
return GNUNET_DB_STATUS_HARD_ERROR;
diff --git a/src/exchangedb/pg_select_deposits_above_serial_id.h b/src/exchangedb/pg_select_coin_deposits_above_serial_id.h
index e29937e08..5202336a4 100644
--- a/src/exchangedb/pg_select_deposits_above_serial_id.h
+++ b/src/exchangedb/pg_select_coin_deposits_above_serial_id.h
@@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file exchangedb/pg_select_deposits_above_serial_id.h
- * @brief implementation of the select_deposits_above_serial_id function for Postgres
+ * @file exchangedb/pg_select_coin_deposits_above_serial_id.h
+ * @brief implementation of the select_coin_deposits_above_serial_id function for Postgres
* @author Christian Grothoff
*/
#ifndef PG_SELECT_DEPOSITS_ABOVE_SERIAL_ID_H
@@ -35,7 +35,7 @@
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_select_deposits_above_serial_id (
+TEH_PG_select_coin_deposits_above_serial_id (
void *cls,
uint64_t serial_id,
TALER_EXCHANGEDB_DepositCallback cb,
diff --git a/src/exchangedb/pg_select_contract.c b/src/exchangedb/pg_select_contract.c
index 4f4a525bd..3e6bf22bc 100644
--- a/src/exchangedb/pg_select_contract.c
+++ b/src/exchangedb/pg_select_contract.c
@@ -27,11 +27,11 @@
enum GNUNET_DB_QueryStatus
TEH_PG_select_contract (void *cls,
- const struct TALER_ContractDiffiePublicP *pub_ckey,
- struct TALER_PurseContractPublicKeyP *purse_pub,
- struct TALER_PurseContractSignatureP *econtract_sig,
- size_t *econtract_size,
- void **econtract)
+ const struct TALER_ContractDiffiePublicP *pub_ckey,
+ struct TALER_PurseContractPublicKeyP *purse_pub,
+ struct TALER_PurseContractSignatureP *econtract_sig,
+ size_t *econtract_size,
+ void **econtract)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -49,15 +49,15 @@ TEH_PG_select_contract (void *cls,
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_select_contract */
+ /* Used in #postgres_select_contract */
PREPARE (pg,
- "select_contract",
- "SELECT "
- " purse_pub"
- ",e_contract"
- ",contract_sig"
- " FROM contracts"
- " WHERE pub_ckey=$1;");
+ "select_contract",
+ "SELECT "
+ " purse_pub"
+ ",e_contract"
+ ",contract_sig"
+ " FROM contracts"
+ " WHERE pub_ckey=$1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_contract",
params,
diff --git a/src/exchangedb/pg_select_contract.h b/src/exchangedb/pg_select_contract.h
index a503c8da9..747a82753 100644
--- a/src/exchangedb/pg_select_contract.h
+++ b/src/exchangedb/pg_select_contract.h
@@ -38,10 +38,10 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_select_contract (void *cls,
- const struct TALER_ContractDiffiePublicP *pub_ckey,
- struct TALER_PurseContractPublicKeyP *purse_pub,
- struct TALER_PurseContractSignatureP *econtract_sig,
- size_t *econtract_size,
+ const struct TALER_ContractDiffiePublicP *pub_ckey,
+ struct TALER_PurseContractPublicKeyP *purse_pub,
+ struct TALER_PurseContractSignatureP *econtract_sig,
+ size_t *econtract_size,
void **econtract);
#endif
diff --git a/src/exchangedb/pg_select_contract_by_purse.c b/src/exchangedb/pg_select_contract_by_purse.c
index aeeb56d48..8d29b3954 100644
--- a/src/exchangedb/pg_select_contract_by_purse.c
+++ b/src/exchangedb/pg_select_contract_by_purse.c
@@ -46,7 +46,7 @@ TEH_PG_select_contract_by_purse (
&econtract->econtract_size),
GNUNET_PQ_result_spec_end
};
- /* Used in #postgres_select_contract_by_purse */
+ /* Used in #postgres_select_contract_by_purse */
PREPARE (pg,
"select_contract_by_purse",
"SELECT "
diff --git a/src/exchangedb/pg_select_deposits_missing_wire.c b/src/exchangedb/pg_select_deposits_missing_wire.c
deleted file mode 100644
index 2a260a369..000000000
--- a/src/exchangedb/pg_select_deposits_missing_wire.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_select_deposits_missing_wire.c
- * @brief Implementation of the select_deposits_missing_wire function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_select_deposits_missing_wire.h"
-#include "pg_helper.h"
-
-/**
- * Closure for #missing_wire_cb().
- */
-struct MissingWireContext
-{
- /**
- * Function to call per result.
- */
- TALER_EXCHANGEDB_WireMissingCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Set to #GNUNET_SYSERR on error.
- */
- enum GNUNET_GenericReturnValue status;
-};
-
-
-/**
- * Invoke the callback for each result.
- *
- * @param cls a `struct MissingWireContext *`
- * @param result SQL result
- * @param num_results number of rows in @a result
- */
-static void
-missing_wire_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct MissingWireContext *mwc = cls;
- struct PostgresClosure *pg = mwc->pg;
-
- while (0 < num_results)
- {
- uint64_t rowid;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount;
- char *payto_uri;
- struct GNUNET_TIME_Timestamp deadline;
- bool done;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("deposit_serial_id",
- &rowid),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount),
- GNUNET_PQ_result_spec_string ("payto_uri",
- &payto_uri),
- GNUNET_PQ_result_spec_timestamp ("wire_deadline",
- &deadline),
- GNUNET_PQ_result_spec_bool ("done",
- &done),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- --num_results))
- {
- GNUNET_break (0);
- mwc->status = GNUNET_SYSERR;
- return;
- }
- mwc->cb (mwc->cb_cls,
- rowid,
- &coin_pub,
- &amount,
- payto_uri,
- deadline,
- done);
- GNUNET_PQ_cleanup_result (rs);
- }
-}
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_select_deposits_missing_wire (void *cls,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- TALER_EXCHANGEDB_WireMissingCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_timestamp (&start_date),
- GNUNET_PQ_query_param_timestamp (&end_date),
- GNUNET_PQ_query_param_end
- };
- struct MissingWireContext mwc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg,
- .status = GNUNET_OK
- };
- enum GNUNET_DB_QueryStatus qs;
-
- /* Used in #postgres_select_deposits_missing_wire */
- // FIXME: used by the auditor; can probably be done
- // smarter by checking if 'done' or 'blocked'
- // are set correctly when going over deposits, instead
- // of JOINing with refunds.
- PREPARE (pg,
- "deposits_get_overdue",
- "SELECT"
- " deposit_serial_id"
- ",coin_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",payto_uri"
- ",wire_deadline"
- ",done"
- " FROM deposits d"
- " JOIN known_coins"
- " USING (coin_pub)"
- " JOIN wire_targets"
- " USING (wire_target_h_payto)"
- " WHERE wire_deadline >= $1"
- " AND wire_deadline < $2"
- " AND NOT (EXISTS (SELECT 1"
- " FROM refunds r"
- " WHERE (r.coin_pub = d.coin_pub) AND (r.deposit_serial_id = d.deposit_serial_id))"
- " OR EXISTS (SELECT 1"
- " FROM aggregation_tracking"
- " WHERE (aggregation_tracking.deposit_serial_id = d.deposit_serial_id)))"
- " ORDER BY wire_deadline ASC");
-
-
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "deposits_get_overdue",
- params,
- &missing_wire_cb,
- &mwc);
- if (GNUNET_OK != mwc.status)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
diff --git a/src/exchangedb/pg_select_deposits_missing_wire.h b/src/exchangedb/pg_select_deposits_missing_wire.h
deleted file mode 100644
index f702c2417..000000000
--- a/src/exchangedb/pg_select_deposits_missing_wire.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_select_deposits_missing_wire.h
- * @brief implementation of the select_deposits_missing_wire function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_SELECT_DEPOSITS_MISSING_WIRE_H
-#define PG_SELECT_DEPOSITS_MISSING_WIRE_H
-
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include "taler_exchangedb_plugin.h"
-/**
- * Select all of those deposits in the database for which we do
- * not have a wire transfer (or a refund) and which should have
- * been deposited between @a start_date and @a end_date.
- *
- * @param cls closure
- * @param start_date lower bound on the requested wire execution date
- * @param end_date upper bound on the requested wire execution date
- * @param cb function to call on all such deposits
- * @param cb_cls closure for @a cb
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-TEH_PG_select_deposits_missing_wire (void *cls,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- TALER_EXCHANGEDB_WireMissingCallback cb,
- void *cb_cls);
-
-#endif
diff --git a/src/exchangedb/pg_select_history_requests_above_serial_id.c b/src/exchangedb/pg_select_history_requests_above_serial_id.c
deleted file mode 100644
index 81e038114..000000000
--- a/src/exchangedb/pg_select_history_requests_above_serial_id.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_select_history_requests_above_serial_id.c
- * @brief Implementation of the select_history_requests_above_serial_id function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_select_history_requests_above_serial_id.h"
-#include "pg_helper.h"
-
-/**
- * Closure for #purse_deposit_serial_helper_cb().
- */
-struct HistoryRequestSerialContext
-{
-
- /**
- * Callback to call.
- */
- TALER_EXCHANGEDB_HistoryRequestCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Status code, set to #GNUNET_SYSERR on hard errors.
- */
- enum GNUNET_GenericReturnValue status;
-};
-
-
-/**
- * Helper function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls closure of type `struct HistoryRequestSerialContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-history_request_serial_helper_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct HistoryRequestSerialContext *dsc = cls;
- struct PostgresClosure *pg = dsc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t rowid;
- struct TALER_Amount history_fee;
- struct GNUNET_TIME_Timestamp ts;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_ReserveSignatureP reserve_sig;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
- &history_fee),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &reserve_pub),
- GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
- &reserve_sig),
- GNUNET_PQ_result_spec_uint64 ("history_request_serial_id",
- &rowid),
- GNUNET_PQ_result_spec_timestamp ("request_timestamp",
- &ts),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_GenericReturnValue ret;
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- dsc->status = GNUNET_SYSERR;
- return;
- }
- ret = dsc->cb (dsc->cb_cls,
- rowid,
- &history_fee,
- ts,
- &reserve_pub,
- &reserve_sig);
- GNUNET_PQ_cleanup_result (rs);
- if (GNUNET_OK != ret)
- break;
- }
-}
-
-
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_select_history_requests_above_serial_id (
- void *cls,
- uint64_t serial_id,
- TALER_EXCHANGEDB_HistoryRequestCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&serial_id),
- GNUNET_PQ_query_param_end
- };
- struct HistoryRequestSerialContext dsc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg,
- .status = GNUNET_OK
- };
- enum GNUNET_DB_QueryStatus qs;
- PREPARE (pg,
- "audit_get_history_requests_incr",
- "SELECT"
- " history_request_serial_id"
- ",history_fee_val"
- ",history_fee_frac"
- ",request_timestamp"
- ",reserve_pub"
- ",reserve_sig"
- " FROM history_requests"
- " WHERE ("
- " (history_request_serial_id>=$1)"
- " )"
- " ORDER BY history_request_serial_id ASC;");
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "audit_get_history_requests_incr",
- params,
- &history_request_serial_helper_cb,
- &dsc);
- if (GNUNET_OK != dsc.status)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
-}
diff --git a/src/exchangedb/pg_select_justification_for_missing_wire.c b/src/exchangedb/pg_select_justification_for_missing_wire.c
new file mode 100644
index 000000000..77d5b4de7
--- /dev/null
+++ b/src/exchangedb/pg_select_justification_for_missing_wire.c
@@ -0,0 +1,89 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_batch_deposits_missing_wire.c
+ * @brief Implementation of the select_batch_deposits_missing_wire function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_batch_deposits_missing_wire.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_justification_for_missing_wire (
+ void *cls,
+ const struct TALER_PaytoHashP *wire_target_h_payto,
+ char **payto_uri,
+ char **kyc_pending,
+ enum TALER_AmlDecisionState *status,
+ struct TALER_Amount *aml_limit)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now
+ = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (wire_target_h_payto),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_end
+ };
+ uint32_t aml_status32;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ payto_uri),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("kyc_pending",
+ kyc_pending),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("aml_status",
+ &aml_status32),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_RESULT_SPEC_AMOUNT ("aml_limit",
+ aml_limit),
+ NULL),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "deposits_get_overdue",
+ "SELECT"
+ " out_payto_uri AS payto_uri"
+ ",out_kyc_pending AS kyc_pending"
+ ",out_deadline AS deadline"
+ ",out_aml_status AS aml_status"
+ ",out_aml_limit AS aml_limit"
+ " FROM exchange_do_select_justification_missing_wire"
+ " ($1, $2);");
+ memset (aml_limit,
+ 0,
+ sizeof (*aml_limit));
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "",
+ params,
+ rs);
+ if (qs <= 0)
+ return qs;
+ *status = (enum TALER_AmlDecisionState) aml_status32;
+ return qs;
+}
diff --git a/src/exchangedb/pg_select_justification_for_missing_wire.h b/src/exchangedb/pg_select_justification_for_missing_wire.h
new file mode 100644
index 000000000..7f73eb511
--- /dev/null
+++ b/src/exchangedb/pg_select_justification_for_missing_wire.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file exchangedb/pg_select_justification_for_missing_wire.h
+ * @brief implementation of the select_justification_for_missing_wire function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_JUSTIFICATION_FOR_MISSING_WIRE_H
+#define PG_SELECT_JUSTIFICATION_FOR_MISSING_WIRE_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Select all of those justifications for why we might not have
+ * done a wire transfer from in the database for a particular target account.
+ *
+ * @param cls closure
+ * @param wire_target_h_payto effected target account
+ * @param[out] payto_uri target account URI, set to NULL if unknown
+ * @param[out] kyc_pending set to string describing missing KYC data
+ * @param[out] status set to AML status
+ * @param[out] aml_limit set to AML limit, or invalid amount for none
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_justification_for_missing_wire (
+ void *cls,
+ const struct TALER_PaytoHashP *wire_target_h_payto,
+ char **payto_uri,
+ char **kyc_pending,
+ enum TALER_AmlDecisionState *status,
+ struct TALER_Amount *aml_limit);
+
+#endif
diff --git a/src/exchangedb/pg_select_kyc_attributes.c b/src/exchangedb/pg_select_kyc_attributes.c
index c9b992da2..99ac43b3e 100644
--- a/src/exchangedb/pg_select_kyc_attributes.c
+++ b/src/exchangedb/pg_select_kyc_attributes.c
@@ -80,14 +80,9 @@ get_attributes_cb (void *cls,
size_t enc_attributes_size;
void *enc_attributes;
char *provider;
- char *birthdate = NULL;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_string ("provider",
&provider),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("birthdate",
- &birthdate),
- NULL),
GNUNET_PQ_result_spec_timestamp ("collection_time",
&collection_time),
GNUNET_PQ_result_spec_timestamp ("expiration_time",
@@ -110,7 +105,6 @@ get_attributes_cb (void *cls,
ctx->cb (ctx->cb_cls,
ctx->h_payto,
provider,
- birthdate,
collection_time,
expiration_time,
enc_attributes_size,
@@ -145,7 +139,6 @@ TEH_PG_select_kyc_attributes (
"select_kyc_attributes",
"SELECT "
" provider"
- ",birthdate"
",collection_time"
",expiration_time"
",encrypted_attributes"
diff --git a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c
index 5cb665fa8..417d78ec7 100644
--- a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c
+++ b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
/**
* Closure for #get_kyc_amounts_cb().
*/
@@ -132,12 +131,11 @@ TEH_PG_select_merge_amounts_for_kyc_check (
};
enum GNUNET_DB_QueryStatus qs;
-
+
PREPARE (pg,
"select_kyc_relevant_merge_events",
"SELECT"
- " amount_with_fee_val AS amount_val"
- ",amount_with_fee_frac AS amount_frac"
+ " amount_with_fee AS amount"
",merge_timestamp AS date"
" FROM account_merges"
" JOIN purse_merges USING (purse_pub)"
@@ -157,4 +155,3 @@ TEH_PG_select_merge_amounts_for_kyc_check (
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
}
-
diff --git a/src/exchangedb/pg_select_purse.c b/src/exchangedb/pg_select_purse.c
index 6496d4a28..ffccb905c 100644
--- a/src/exchangedb/pg_select_purse.c
+++ b/src/exchangedb/pg_select_purse.c
@@ -36,7 +36,8 @@ TEH_PG_select_purse (
struct TALER_Amount *deposited,
struct TALER_PrivateContractHashP *h_contract_terms,
struct GNUNET_TIME_Timestamp *merge_timestamp,
- bool *purse_deleted)
+ bool *purse_deleted,
+ bool *purse_refunded)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -60,6 +61,10 @@ TEH_PG_select_purse (
NULL),
GNUNET_PQ_result_spec_bool ("purse_deleted",
purse_deleted),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_bool ("purse_refunded",
+ purse_refunded),
+ NULL),
GNUNET_PQ_result_spec_end
};
@@ -70,17 +75,18 @@ TEH_PG_select_purse (
",pr.purse_creation"
",pr.purse_expiration"
",pr.h_contract_terms"
- ",pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
- ",pr.balance_val"
- ",pr.balance_frac"
+ ",pr.amount_with_fee"
+ ",pr.balance"
",pm.merge_timestamp"
",pd.purse_sig IS NOT NULL AS purse_deleted"
+ ",pc.refunded AS purse_refunded"
" FROM purse_requests pr"
" LEFT JOIN purse_merges pm ON (pm.purse_pub = pr.purse_pub)"
+ " LEFT JOIN purse_decision pc ON (pc.purse_pub = pr.purse_pub)"
" LEFT JOIN purse_deletion pd ON (pd.purse_pub = pr.purse_pub)"
" WHERE pr.purse_pub=$1;");
*merge_timestamp = GNUNET_TIME_UNIT_FOREVER_TS;
+ *purse_refunded = false;
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_purse",
params,
diff --git a/src/exchangedb/pg_select_purse.h b/src/exchangedb/pg_select_purse.h
index db63f0c90..8f88c5cf7 100644
--- a/src/exchangedb/pg_select_purse.h
+++ b/src/exchangedb/pg_select_purse.h
@@ -38,6 +38,7 @@
* @param[out] h_contract_terms set to hash of the contract for the purse
* @param[out] merge_timestamp set to time when the purse was merged, or NEVER if not
* @param[out] purse_deleted set to true if purse was deleted
+ * @param[out] purse_refunded set to true if purse was refunded
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -50,7 +51,7 @@ TEH_PG_select_purse (
struct TALER_Amount *deposited,
struct TALER_PrivateContractHashP *h_contract_terms,
struct GNUNET_TIME_Timestamp *merge_timestamp,
- bool *purse_deleted);
-
+ bool *purse_deleted,
+ bool *purse_refunded);
#endif
diff --git a/src/exchangedb/pg_select_purse_by_merge_pub.c b/src/exchangedb/pg_select_purse_by_merge_pub.c
index 965b27ba3..d035b3255 100644
--- a/src/exchangedb/pg_select_purse_by_merge_pub.c
+++ b/src/exchangedb/pg_select_purse_by_merge_pub.c
@@ -60,7 +60,6 @@ TEH_PG_select_purse_by_merge_pub (
GNUNET_PQ_result_spec_end
};
-
PREPARE (pg,
"select_purse_by_merge_pub",
"SELECT "
@@ -68,14 +67,11 @@ TEH_PG_select_purse_by_merge_pub (
",purse_expiration"
",h_contract_terms"
",age_limit"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
- ",balance_val"
- ",balance_frac"
+ ",amount_with_fee"
+ ",balance"
",purse_sig"
" FROM purse_requests"
" WHERE merge_pub=$1;");
-
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_purse_by_merge_pub",
params,
diff --git a/src/exchangedb/pg_select_purse_decisions_above_serial_id.c b/src/exchangedb/pg_select_purse_decisions_above_serial_id.c
index 2368f2d3e..f301ea78a 100644
--- a/src/exchangedb/pg_select_purse_decisions_above_serial_id.c
+++ b/src/exchangedb/pg_select_purse_decisions_above_serial_id.c
@@ -112,7 +112,6 @@ purse_decision_serial_helper_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_purse_decisions_above_serial_id (
void *cls,
@@ -141,8 +140,7 @@ TEH_PG_select_purse_decisions_above_serial_id (
" pd.purse_pub"
",pm.reserve_pub"
",pd.purse_decision_serial_id"
- ",pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
+ ",pr.amount_with_fee"
" FROM purse_decision pd"
" JOIN purse_requests pr ON (pd.purse_pub = pr.purse_pub)"
" LEFT JOIN purse_merges pm ON (pm.purse_pub = pd.purse_pub)"
diff --git a/src/exchangedb/pg_select_purse_decisions_above_serial_id.h b/src/exchangedb/pg_select_purse_decisions_above_serial_id.h
index 53ab31c80..83168d546 100644
--- a/src/exchangedb/pg_select_purse_decisions_above_serial_id.h
+++ b/src/exchangedb/pg_select_purse_decisions_above_serial_id.h
@@ -43,4 +43,5 @@ TEH_PG_select_purse_decisions_above_serial_id (
bool refunded,
TALER_EXCHANGEDB_PurseDecisionCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_select_purse_deposits_above_serial_id.c b/src/exchangedb/pg_select_purse_deposits_above_serial_id.c
index 72fdcd99b..bb4320663 100644
--- a/src/exchangedb/pg_select_purse_deposits_above_serial_id.c
+++ b/src/exchangedb/pg_select_purse_deposits_above_serial_id.c
@@ -168,12 +168,9 @@ TEH_PG_select_purse_deposits_above_serial_id (
PREPARE (pg,
"audit_get_purse_deposits_incr",
"SELECT"
- " pd.amount_with_fee_val"
- ",pd.amount_with_fee_frac"
- ",pr.amount_with_fee_val AS total_val"
- ",pr.amount_with_fee_frac AS total_frac"
- ",pr.balance_val"
- ",pr.balance_frac"
+ " pd.amount_with_fee"
+ ",pr.amount_with_fee AS total"
+ ",pr.balance"
",pr.flags"
",pd.purse_pub"
",pd.coin_sig"
diff --git a/src/exchangedb/pg_select_purse_deposits_by_purse.c b/src/exchangedb/pg_select_purse_deposits_by_purse.c
index 5fe7e014b..94b935cb4 100644
--- a/src/exchangedb/pg_select_purse_deposits_by_purse.c
+++ b/src/exchangedb/pg_select_purse_deposits_by_purse.c
@@ -133,15 +133,15 @@ TEH_PG_select_purse_deposits_by_purse (
"audit_get_purse_deposits_by_purse",
"SELECT"
" pd.purse_deposit_serial_id"
- ",pd.amount_with_fee_val"
- ",pd.amount_with_fee_frac"
+ ",pd.amount_with_fee"
",pd.coin_pub"
",denom.denom_pub"
" FROM purse_deposits pd"
- " JOIN known_coins kc USING (coin_pub)"
- " JOIN denominations denom USING (denominations_serial)"
+ " JOIN known_coins kc"
+ " USING (coin_pub)"
+ " JOIN denominations denom"
+ " USING (denominations_serial)"
" WHERE purse_pub=$1;");
-
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"audit_get_purse_deposits_by_purse",
params,
diff --git a/src/exchangedb/pg_select_purse_merge.c b/src/exchangedb/pg_select_purse_merge.c
index d1f6a5396..ecc047cc5 100644
--- a/src/exchangedb/pg_select_purse_merge.c
+++ b/src/exchangedb/pg_select_purse_merge.c
@@ -33,14 +33,14 @@ TEH_PG_select_purse_merge (
struct TALER_PurseMergeSignatureP *merge_sig,
struct GNUNET_TIME_Timestamp *merge_timestamp,
char **partner_url,
- struct TALER_ReservePublicKeyP *reserve_pub)
+ struct TALER_ReservePublicKeyP *reserve_pub,
+ bool *refunded)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (purse_pub),
GNUNET_PQ_query_param_end
};
- bool is_null;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("merge_sig",
merge_sig),
@@ -51,22 +51,28 @@ TEH_PG_select_purse_merge (
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_string ("partner_base_url",
partner_url),
- &is_null),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_bool ("refunded",
+ refunded),
+ NULL),
GNUNET_PQ_result_spec_end
};
*partner_url = NULL;
- /* Used in #postgres_select_purse_merge */
+ *refunded = false;
PREPARE (pg,
"select_purse_merge",
"SELECT "
- " reserve_pub"
- ",merge_sig"
- ",merge_timestamp"
- ",partner_base_url"
- " FROM purse_merges"
- " LEFT JOIN partners USING (partner_serial_id)"
- " WHERE purse_pub=$1;");
+ " pm.reserve_pub"
+ ",pm.merge_sig"
+ ",pm.merge_timestamp"
+ ",pr.partner_base_url"
+ ",pd.refunded"
+ " FROM purse_merges pm"
+ " LEFT JOIN purse_decision pd USING (purse_pub)"
+ " LEFT JOIN partners pr USING (partner_serial_id)"
+ " WHERE pm.purse_pub=$1;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"select_purse_merge",
params,
diff --git a/src/exchangedb/pg_select_purse_merge.h b/src/exchangedb/pg_select_purse_merge.h
index 982225123..8054974aa 100644
--- a/src/exchangedb/pg_select_purse_merge.h
+++ b/src/exchangedb/pg_select_purse_merge.h
@@ -35,6 +35,7 @@
* @param[out] merge_timestamp set to the time of the merge
* @param[out] partner_url set to the URL of the target exchange, or NULL if the target exchange is us. To be freed by the caller.
* @param[out] reserve_pub set to the public key of the reserve/account being credited
+ * @param[out] refunded set to true if purse was refunded
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -44,6 +45,7 @@ TEH_PG_select_purse_merge (
struct TALER_PurseMergeSignatureP *merge_sig,
struct GNUNET_TIME_Timestamp *merge_timestamp,
char **partner_url,
- struct TALER_ReservePublicKeyP *reserve_pub);
+ struct TALER_ReservePublicKeyP *reserve_pub,
+ bool *refunded);
#endif
diff --git a/src/exchangedb/pg_select_purse_merges_above_serial_id.c b/src/exchangedb/pg_select_purse_merges_above_serial_id.c
index 748a92b73..cd06d65e9 100644
--- a/src/exchangedb/pg_select_purse_merges_above_serial_id.c
+++ b/src/exchangedb/pg_select_purse_merges_above_serial_id.c
@@ -163,10 +163,8 @@ TEH_PG_select_purse_merges_above_serial_id (
"SELECT"
" pm.purse_merge_request_serial_id"
",partner_base_url"
- ",pr.amount_with_fee_val"
- ",pr.amount_with_fee_frac"
- ",pr.balance_val"
- ",pr.balance_frac"
+ ",pr.amount_with_fee"
+ ",pr.balance"
",pr.flags"
",pr.merge_pub"
",pm.reserve_pub"
diff --git a/src/exchangedb/pg_select_purse_requests_above_serial_id.c b/src/exchangedb/pg_select_purse_requests_above_serial_id.c
index 51f5de82c..61a4f2041 100644
--- a/src/exchangedb/pg_select_purse_requests_above_serial_id.c
+++ b/src/exchangedb/pg_select_purse_requests_above_serial_id.c
@@ -155,8 +155,7 @@ TEH_PG_select_purse_requests_above_serial_id (
"SELECT"
" purse_requests_serial_id"
",purse_pub"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",age_limit"
",h_contract_terms"
",purse_creation"
diff --git a/src/exchangedb/pg_select_recoup_above_serial_id.c b/src/exchangedb/pg_select_recoup_above_serial_id.c
index 9047a86f8..5791ee500 100644
--- a/src/exchangedb/pg_select_recoup_above_serial_id.c
+++ b/src/exchangedb/pg_select_recoup_above_serial_id.c
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
/**
* Closure for #recoup_serial_helper_cb().
*/
@@ -77,7 +76,7 @@ recoup_serial_helper_cb (void *cls,
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_CoinPublicInfo coin;
struct TALER_CoinSpendSignatureP coin_sig;
- union TALER_DenominationBlindingKeyP coin_blind;
+ union GNUNET_CRYPTO_BlindingSecretP coin_blind;
struct TALER_Amount amount;
struct TALER_DenominationPublicKey denom_pub;
struct TALER_BlindedCoinHashP h_blind_ev;
@@ -137,6 +136,7 @@ recoup_serial_helper_cb (void *cls,
}
}
+
enum GNUNET_DB_QueryStatus
TEH_PG_select_recoup_above_serial_id (
void *cls,
@@ -157,7 +157,6 @@ TEH_PG_select_recoup_above_serial_id (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_recoup_above_serial_id() to obtain recoup transactions */
PREPARE (pg,
"recoup_get_incr",
"SELECT"
@@ -172,8 +171,7 @@ TEH_PG_select_recoup_above_serial_id (
",coins.denom_sig"
",coins.age_commitment_hash"
",denoms.denom_pub"
- ",amount_val"
- ",amount_frac"
+ ",amount"
" FROM recoup"
" JOIN known_coins coins"
" USING (coin_pub)"
diff --git a/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c b/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c
index a3f6bc93d..22f906738 100644
--- a/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c
+++ b/src/exchangedb/pg_select_recoup_refresh_above_serial_id.c
@@ -76,7 +76,7 @@ recoup_refresh_serial_helper_cb (void *cls,
struct TALER_CoinSpendPublicKeyP old_coin_pub;
struct TALER_CoinPublicInfo coin;
struct TALER_CoinSpendSignatureP coin_sig;
- union TALER_DenominationBlindingKeyP coin_blind;
+ union GNUNET_CRYPTO_BlindingSecretP coin_blind;
struct TALER_DenominationPublicKey denom_pub;
struct TALER_DenominationHashP old_denom_pub_hash;
struct TALER_Amount amount;
@@ -141,7 +141,6 @@ recoup_refresh_serial_helper_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_recoup_refresh_above_serial_id (
void *cls,
@@ -162,8 +161,6 @@ TEH_PG_select_recoup_refresh_above_serial_id (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_recoup_refresh_above_serial_id() to obtain
- recoup-refresh transactions */
PREPARE (pg,
"recoup_refresh_get_incr",
"SELECT"
@@ -179,8 +176,7 @@ TEH_PG_select_recoup_refresh_above_serial_id (
",rrc.h_coin_ev AS h_blind_ev"
",new_denoms.denom_pub_hash"
",new_coins.denom_sig AS denom_sig"
- ",amount_val"
- ",amount_frac"
+ ",amount"
" FROM recoup_refresh"
" INNER JOIN refresh_revealed_coins rrc"
" USING (rrc_serial)"
diff --git a/src/exchangedb/pg_select_refreshes_above_serial_id.c b/src/exchangedb/pg_select_refreshes_above_serial_id.c
index d2b4a7fa6..db432269c 100644
--- a/src/exchangedb/pg_select_refreshes_above_serial_id.c
+++ b/src/exchangedb/pg_select_refreshes_above_serial_id.c
@@ -130,10 +130,6 @@ refreshs_serial_helper_cb (void *cls,
}
-
-
-
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_refreshes_above_serial_id (
void *cls,
@@ -153,8 +149,7 @@ TEH_PG_select_refreshes_above_serial_id (
.status = GNUNET_OK
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_refreshes_above_serial_id() to fetch
- refresh session with id '\geq' the given parameter */
+
PREPARE (pg,
"audit_get_refresh_commitments_incr",
"SELECT"
@@ -162,8 +157,7 @@ TEH_PG_select_refreshes_above_serial_id (
",kc.coin_pub AS old_coin_pub"
",kc.age_commitment_hash"
",old_coin_sig"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",noreveal_index"
",melt_serial_id"
",rc"
diff --git a/src/exchangedb/pg_select_refunds_above_serial_id.c b/src/exchangedb/pg_select_refunds_above_serial_id.c
index d8c87d7d4..396e8d3d5 100644
--- a/src/exchangedb/pg_select_refunds_above_serial_id.c
+++ b/src/exchangedb/pg_select_refunds_above_serial_id.c
@@ -182,20 +182,21 @@ TEH_PG_select_refunds_above_serial_id (
PREPARE (pg,
"audit_get_refunds_incr",
"SELECT"
- " dep.merchant_pub"
+ " bdep.merchant_pub"
",ref.merchant_sig"
- ",dep.h_contract_terms"
+ ",bdep.h_contract_terms"
",ref.rtransaction_id"
",denom.denom_pub"
",kc.coin_pub"
- ",ref.amount_with_fee_val"
- ",ref.amount_with_fee_frac"
+ ",ref.amount_with_fee"
",ref.refund_serial_id"
" FROM refunds ref"
- " JOIN deposits dep"
- " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)"
+ " JOIN batch_deposits bdep"
+ " ON (ref.batch_deposit_serial_id=bdep.batch_deposit_serial_id)"
+ " JOIN coin_deposits cdep"
+ " ON (ref.coin_pub=cdep.coin_pub AND ref.batch_deposit_serial_id=cdep.batch_deposit_serial_id)"
" JOIN known_coins kc"
- " ON (dep.coin_pub=kc.coin_pub)"
+ " ON (cdep.coin_pub=kc.coin_pub)"
" JOIN denominations denom"
" ON (kc.denominations_serial=denom.denominations_serial)"
" WHERE ref.refund_serial_id>=$1"
@@ -203,16 +204,14 @@ TEH_PG_select_refunds_above_serial_id (
PREPARE (pg,
"test_refund_full",
"SELECT"
- " CAST(SUM(CAST(ref.amount_with_fee_frac AS INT8)) AS INT8) AS s_f"
- ",CAST(SUM(ref.amount_with_fee_val) AS INT8) AS s_v"
- ",dep.amount_with_fee_val"
- ",dep.amount_with_fee_frac"
+ " CAST(SUM(CAST((ref.amount_with_fee).frac AS INT8)) AS INT8) AS s_f"
+ ",CAST(SUM((ref.amount_with_fee).val) AS INT8) AS s_v"
+ ",cdep.amount_with_fee"
" FROM refunds ref"
- " JOIN deposits dep"
- " ON (ref.coin_pub=dep.coin_pub AND ref.deposit_serial_id=dep.deposit_serial_id)"
+ " JOIN coin_deposits cdep"
+ " ON (ref.coin_pub=cdep.coin_pub AND ref.batch_deposit_serial_id=cdep.batch_deposit_serial_id)"
" WHERE ref.refund_serial_id=$1"
- " GROUP BY (dep.amount_with_fee_val, dep.amount_with_fee_frac);");
-
+ " GROUP BY (cdep.amount_with_fee);");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"audit_get_refunds_incr",
params,
diff --git a/src/exchangedb/pg_select_refunds_by_coin.c b/src/exchangedb/pg_select_refunds_by_coin.c
index 7325b3597..d9cd6dd3c 100644
--- a/src/exchangedb/pg_select_refunds_by_coin.c
+++ b/src/exchangedb/pg_select_refunds_by_coin.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-2023 Taler Systems SA
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
@@ -49,7 +49,7 @@ struct SelectRefundContext
/**
* Set to #GNUNET_SYSERR on error.
*/
- int status;
+ enum GNUNET_GenericReturnValue status;
};
@@ -112,219 +112,29 @@ TEH_PG_select_refunds_by_coin (
GNUNET_PQ_query_param_auto_from_type (h_contract),
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_QueryParam params5[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_end
- };
-
struct SelectRefundContext srctx = {
.cb = cb,
.cb_cls = cb_cls,
.pg = pg,
.status = GNUNET_OK
};
- static int percent_refund = -2;
- const char *query;
- struct GNUNET_PQ_QueryParam *xparams = params;
-
- if (-2 == percent_refund)
- {
- const char *mode = getenv ("TALER_POSTGRES_SELECT_REFUNDS_BY_COIN_LOGIC");
- char dummy;
-
- if ( (NULL==mode) ||
- (1 != sscanf (mode,
- "%d%c",
- &percent_refund,
- &dummy)) )
- {
- if (NULL != mode)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Bad mode `%s' specified\n",
- mode);
- percent_refund = 0;
- }
- }
-
- switch (percent_refund)
- {
- case 0:
- query = "get_refunds_by_coin_and_contract-v0";
- PREPARE (pg,
- query,
- "SELECT"
- " ref.amount_with_fee_val"
- ",ref.amount_with_fee_frac"
- " FROM refunds ref"
- " JOIN deposits dep"
- " USING (coin_pub,deposit_serial_id)"
- " WHERE ref.coin_pub=$1"
- " AND dep.merchant_pub=$2"
- " AND dep.h_contract_terms=$3;");
- break;
- case 1:
- query = "get_refunds_by_coin_and_contract-v1";
- PREPARE (pg,
- query,
- "SELECT"
- " ref.amount_with_fee_val"
- ",ref.amount_with_fee_frac"
- " FROM refunds ref"
- " LEFT JOIN deposits dep"
- " ON dep.coin_pub = ref.coin_pub"
- " AND ref.deposit_serial_id = dep.deposit_serial_id"
- " WHERE ref.coin_pub=$1"
- " AND dep.merchant_pub=$2"
- " AND dep.h_contract_terms=$3;");
- break;
- case 2:
- query = "get_refunds_by_coin_and_contract-v2";
- PREPARE (pg,
- query,
- "WITH rc AS MATERIALIZED("
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",coin_pub"
- ",deposit_serial_id"
- " FROM refunds ref"
- " WHERE ref.coin_pub=$1)"
- "SELECT"
- " rc.amount_with_fee_val"
- " ,rc.amount_with_fee_frac"
- " FROM deposits dep"
- " JOIN rc"
- " ON rc.deposit_serial_id = dep.deposit_serial_id"
- " WHERE"
- " dep.coin_pub = $1"
- " AND dep.merchant_pub = $2"
- " AND dep.h_contract_terms = $3");
- break;
- case 3:
- query = "get_refunds_by_coin_and_contract-v3";
- PREPARE (pg,
- query,
- "WITH rc AS MATERIALIZED("
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",deposit_serial_id"
- " FROM refunds"
- " WHERE coin_pub=$1)"
- "SELECT"
- " rc.amount_with_fee_val"
- " ,rc.amount_with_fee_frac"
- " FROM ("
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- " FROM deposits depos"
- " WHERE"
- " depos.coin_pub = $1"
- " AND depos.merchant_pub = $2"
- " AND depos.h_contract_terms = $3) dep, rc;");
- break;
- case 4:
- query = "get_refunds_by_coin_and_contract-v4";
- PREPARE (pg,
- query,
- "WITH rc AS MATERIALIZED("
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",coin_pub"
- ",deposit_serial_id"
- " FROM refunds ref"
- " WHERE ref.coin_pub=$1)"
- "SELECT"
- " rc.amount_with_fee_val"
- " ,rc.amount_with_fee_frac"
- " ,deposit_serial_id"
- " FROM ("
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- " FROM deposits depos"
- " WHERE"
- " depos.merchant_pub = $2"
- " AND depos.h_contract_terms = $3) dep JOIN rc "
- "USING(deposit_serial_id, coin_pub);");
- break;
- case 5:
- query = "get_refunds_by_coin_and_contract-v-broken";
- xparams = params5;
- PREPARE (pg,
- query,
- "SELECT"
- " amount_with_fee_val"
- ",amount_with_fee_frac"
- ",coin_pub"
- ",deposit_serial_id"
- " FROM refunds"
- " WHERE coin_pub=$1;");
- break;
- case 8:
- query = "get_refunds_by_coin_and_contract-v8";
- PREPARE (pg,
- query,
- "WITH"
- " rc AS MATERIALIZED("
- " SELECT"
- " amount_with_fee_val"
- " ,amount_with_fee_frac"
- " ,coin_pub"
- " ,deposit_serial_id"
- " FROM refunds"
- " WHERE coin_pub=$1),"
- " dep AS MATERIALIZED("
- " SELECT"
- " deposit_serial_id"
- " FROM deposits"
- " WHERE coin_pub = $1"
- " AND merchant_pub = $2"
- " AND h_contract_terms = $3"
- ")"
- "SELECT"
- " rc.amount_with_fee_val"
- " ,rc.amount_with_fee_frac"
- " FROM "
- " rc JOIN dep USING (deposit_serial_id);");
- break;
- case 9:
- query = "get_refunds_by_coin_and_contract-v9-broken";
- PREPARE (pg,
- query,
- "SELECT"
- " ref.amount_with_fee_val"
- " ,ref.amount_with_fee_frac"
- " FROM deposits dep"
- " JOIN refunds ref USING(deposit_serial_id)"
- " WHERE dep.coin_pub IN ("
- " SELECT coin_pub"
- " FROM refunds"
- " WHERE coin_pub=$1)"
- " AND merchant_pub = $2"
- " AND h_contract_terms = $3;");
- break;
- case 10:
- query = "get_refunds_by_coin_and_contract-v10-broken";
- PREPARE (pg,
- query,
- "SELECT"
- " *"
- " FROM"
- " exchange_do_refund_by_coin"
- " ($1, $2, $3) "
- " AS (amount_with_fee_val INT8, amount_with_fee_frac INT4);");
- break;
- default:
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
+ const char *query = "get_refunds_by_coin_and_contract";
+
+ PREPARE (pg,
+ query,
+ "SELECT"
+ " ref.amount_with_fee"
+ " FROM refunds ref"
+ " JOIN coin_deposits cdep"
+ " USING (coin_pub,batch_deposit_serial_id)"
+ " JOIN batch_deposits bdep"
+ " ON (ref.batch_deposit_serial_id = bdep.batch_deposit_serial_id)"
+ " WHERE ref.coin_pub=$1"
+ " AND bdep.merchant_pub=$2"
+ " AND bdep.h_contract_terms=$3;");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
query,
- xparams,
+ params,
&get_refunds_cb,
&srctx);
if (GNUNET_SYSERR == srctx.status)
diff --git a/src/exchangedb/pg_select_refunds_by_coin.h b/src/exchangedb/pg_select_refunds_by_coin.h
index e1838b235..72df13fda 100644
--- a/src/exchangedb/pg_select_refunds_by_coin.h
+++ b/src/exchangedb/pg_select_refunds_by_coin.h
@@ -44,4 +44,5 @@ TEH_PG_select_refunds_by_coin (
const struct TALER_PrivateContractHashP *h_contract,
TALER_EXCHANGEDB_RefundCoinCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_select_reserve_close_info.c b/src/exchangedb/pg_select_reserve_close_info.c
index 973f5fa51..eccba8e4c 100644
--- a/src/exchangedb/pg_select_reserve_close_info.c
+++ b/src/exchangedb/pg_select_reserve_close_info.c
@@ -39,7 +39,8 @@ TEH_PG_select_reserve_close_info (
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ TALER_PQ_result_spec_amount ("current_balance",
+ pg->currency,
balance),
GNUNET_PQ_result_spec_string ("payto_uri",
payto_uri),
@@ -49,8 +50,7 @@ TEH_PG_select_reserve_close_info (
PREPARE (pg,
"select_reserve_close_info",
"SELECT "
- " r.current_balance_val"
- ",r.current_balance_frac"
+ " r.current_balance"
",wt.payto_uri"
" FROM reserves r"
" LEFT JOIN reserves_in ri USING (reserve_pub)"
diff --git a/src/exchangedb/pg_select_reserve_closed_above_serial_id.c b/src/exchangedb/pg_select_reserve_closed_above_serial_id.c
index 985c6792c..d24d6a600 100644
--- a/src/exchangedb/pg_select_reserve_closed_above_serial_id.c
+++ b/src/exchangedb/pg_select_reserve_closed_above_serial_id.c
@@ -157,10 +157,8 @@ TEH_PG_select_reserve_closed_above_serial_id (
",execution_date"
",wtid"
",payto_uri AS receiver_account"
- ",amount_val"
- ",amount_frac"
- ",closing_fee_val"
- ",closing_fee_frac"
+ ",amount"
+ ",closing_fee"
",close_request_row"
" FROM reserves_close"
" JOIN wire_targets"
diff --git a/src/exchangedb/pg_select_reserve_open_above_serial_id.c b/src/exchangedb/pg_select_reserve_open_above_serial_id.c
index cc33bc48c..1675e71a7 100644
--- a/src/exchangedb/pg_select_reserve_open_above_serial_id.c
+++ b/src/exchangedb/pg_select_reserve_open_above_serial_id.c
@@ -152,8 +152,7 @@ TEH_PG_select_reserve_open_above_serial_id (
",request_timestamp"
",expiration_date"
",reserve_sig"
- ",reserve_payment_val"
- ",reserve_payment_frac"
+ ",reserve_payment"
",requested_purse_limit"
" FROM reserves_open_requests"
" WHERE open_request_uuid>=$1"
diff --git a/src/exchangedb/pg_select_reserves_in_above_serial_id.c b/src/exchangedb/pg_select_reserves_in_above_serial_id.c
index 1a6efc66b..21033e80d 100644
--- a/src/exchangedb/pg_select_reserves_in_above_serial_id.c
+++ b/src/exchangedb/pg_select_reserves_in_above_serial_id.c
@@ -137,15 +137,12 @@ TEH_PG_select_reserves_in_above_serial_id (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
- transactions for reserves with serial id '\geq' the given parameter */
PREPARE (pg,
"audit_reserves_in_get_transactions_incr",
"SELECT"
" reserves.reserve_pub"
",wire_reference"
- ",credit_val"
- ",credit_frac"
+ ",credit"
",execution_date"
",payto_uri AS sender_account_details"
",reserve_in_serial_id"
diff --git a/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c b/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c
index ba73994f0..1c7bc15a0 100644
--- a/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c
+++ b/src/exchangedb/pg_select_reserves_in_above_serial_id_by_account.c
@@ -24,6 +24,8 @@
#include "taler_pq_lib.h"
#include "pg_select_reserves_in_above_serial_id_by_account.h"
#include "pg_helper.h"
+
+
/**
* Closure for #reserves_in_serial_helper_cb().
*/
@@ -138,15 +140,12 @@ TEH_PG_select_reserves_in_above_serial_id_by_account (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
- transactions for reserves with serial id '\geq' the given parameter */
PREPARE (pg,
"audit_reserves_in_get_transactions_incr_by_account",
"SELECT"
" reserves.reserve_pub"
",wire_reference"
- ",credit_val"
- ",credit_frac"
+ ",credit"
",execution_date"
",payto_uri AS sender_account_details"
",reserve_in_serial_id"
@@ -155,9 +154,9 @@ TEH_PG_select_reserves_in_above_serial_id_by_account (
" USING (reserve_pub)"
" JOIN wire_targets"
" ON (wire_source_h_payto = wire_target_h_payto)"
- " WHERE reserve_in_serial_id>=$1 AND exchange_account_section=$2"
- " ORDER BY reserve_in_serial_id;");
-
+ " WHERE reserve_in_serial_id>=$1"
+ " AND exchange_account_section=$2"
+ " ORDER BY reserve_in_serial_id ASC;");
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"audit_reserves_in_get_transactions_incr_by_account",
params,
diff --git a/src/exchangedb/pg_select_similar_kyc_attributes.c b/src/exchangedb/pg_select_similar_kyc_attributes.c
index a07f2a147..342f9ef33 100644
--- a/src/exchangedb/pg_select_similar_kyc_attributes.c
+++ b/src/exchangedb/pg_select_similar_kyc_attributes.c
@@ -76,16 +76,11 @@ get_attributes_cb (void *cls,
size_t enc_attributes_size;
void *enc_attributes;
char *provider;
- char *birthdate = NULL;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_payto",
&h_payto),
GNUNET_PQ_result_spec_string ("provider",
&provider),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("birthdate",
- &birthdate),
- NULL),
GNUNET_PQ_result_spec_timestamp ("collection_time",
&collection_time),
GNUNET_PQ_result_spec_timestamp ("expiration_time",
@@ -108,7 +103,6 @@ get_attributes_cb (void *cls,
ctx->cb (ctx->cb_cls,
&h_payto,
provider,
- birthdate,
collection_time,
expiration_time,
enc_attributes_size,
@@ -143,7 +137,6 @@ TEH_PG_select_similar_kyc_attributes (
"SELECT "
" h_payto"
",provider"
- ",birthdate"
",collection_time"
",expiration_time"
",encrypted_attributes"
diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id.c b/src/exchangedb/pg_select_wire_out_above_serial_id.c
index e219f5d4b..8668c429d 100644
--- a/src/exchangedb/pg_select_wire_out_above_serial_id.c
+++ b/src/exchangedb/pg_select_wire_out_above_serial_id.c
@@ -113,7 +113,6 @@ wire_out_serial_helper_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_wire_out_above_serial_id (
void *cls,
@@ -133,7 +132,7 @@ TEH_PG_select_wire_out_above_serial_id (
.status = GNUNET_OK
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_wire_out_above_serial_id() */
+ /* Used in #postgres_select_wire_out_above_serial_id() */
PREPARE (pg,
"audit_get_wire_incr",
"SELECT"
@@ -141,8 +140,7 @@ TEH_PG_select_wire_out_above_serial_id (
",execution_date"
",wtid_raw"
",payto_uri"
- ",amount_val"
- ",amount_frac"
+ ",amount"
" FROM wire_out"
" JOIN wire_targets"
" USING (wire_target_h_payto)"
diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c
index 08883c9a4..3448c5a49 100644
--- a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c
+++ b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.c
@@ -112,6 +112,7 @@ wire_out_serial_helper_cb (void *cls,
}
}
+
enum GNUNET_DB_QueryStatus
TEH_PG_select_wire_out_above_serial_id_by_account (
void *cls,
@@ -134,7 +135,6 @@ TEH_PG_select_wire_out_above_serial_id_by_account (
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_wire_out_above_serial_id_by_account() */
PREPARE (pg,
"audit_get_wire_incr_by_account",
"SELECT"
@@ -142,8 +142,7 @@ TEH_PG_select_wire_out_above_serial_id_by_account (
",execution_date"
",wtid_raw"
",payto_uri"
- ",amount_val"
- ",amount_frac"
+ ",amount"
" FROM wire_out"
" JOIN wire_targets"
" USING (wire_target_h_payto)"
diff --git a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h
index 98315cace..04c6a62b2 100644
--- a/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h
+++ b/src/exchangedb/pg_select_wire_out_above_serial_id_by_account.h
@@ -43,4 +43,5 @@ TEH_PG_select_wire_out_above_serial_id_by_account (
uint64_t serial_id,
TALER_EXCHANGEDB_WireTransferOutCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
index e200da8de..71ed81833 100644
--- a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
+++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
@@ -131,21 +131,21 @@ TEH_PG_select_withdraw_amounts_for_kyc_check (
.status = GNUNET_OK
};
enum GNUNET_DB_QueryStatus qs;
- /* Used in #postgres_select_withdraw_amounts_for_kyc_check (
-() */
+
PREPARE (pg,
- "select_kyc_relevant_withdraw_events",
- "SELECT"
- " ro.amount_with_fee_val AS amount_val"
- ",ro.amount_with_fee_frac AS amount_frac"
- ",ro.execution_date AS date"
- " FROM reserves_out ro"
- " JOIN reserves_out_by_reserve USING (h_blind_ev)"
- " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)"
- " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)"
- " WHERE wire_source_h_payto=$1"
- " AND ro.execution_date >= $2"
- " ORDER BY ro.execution_date DESC");
+ "select_kyc_relevant_withdraw_events",
+ "SELECT"
+ " ro.amount_with_fee AS amount"
+ ",ro.execution_date AS date"
+ " FROM reserves_in ri"
+ " JOIN reserve_history rh"
+ " ON (rh.reserve_pub = ri.reserve_pub)"
+ " JOIN reserves_out ro"
+ " ON (ro.reserve_out_serial_id = rh.serial_id)"
+ " WHERE ri.wire_source_h_payto=$1"
+ " AND rh.table_name='reserves_out'"
+ " AND ro.execution_date >= $2"
+ " ORDER BY rh.reserve_history_serial_id DESC");
qs = GNUNET_PQ_eval_prepared_multi_select (
pg->conn,
"select_kyc_relevant_withdraw_events",
diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h
index 4c1283744..9a780adbe 100644
--- a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h
+++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h
@@ -44,4 +44,5 @@ TEH_PG_select_withdraw_amounts_for_kyc_check (
struct GNUNET_TIME_Absolute time_limit,
TALER_EXCHANGEDB_KycAmountCallback kac,
void *kac_cls);
+
#endif
diff --git a/src/exchangedb/pg_select_withdrawals_above_serial_id.c b/src/exchangedb/pg_select_withdrawals_above_serial_id.c
index 4718a62ae..9beb0f936 100644
--- a/src/exchangedb/pg_select_withdrawals_above_serial_id.c
+++ b/src/exchangedb/pg_select_withdrawals_above_serial_id.c
@@ -121,7 +121,6 @@ reserves_out_serial_helper_cb (void *cls,
}
-
enum GNUNET_DB_QueryStatus
TEH_PG_select_withdrawals_above_serial_id (
void *cls,
@@ -142,8 +141,7 @@ TEH_PG_select_withdrawals_above_serial_id (
};
enum GNUNET_DB_QueryStatus qs;
- /* Fetch deposits with rowid '\geq' the given parameter */
-
+ /* Fetch deposits with rowid '\geq' the given parameter */
PREPARE (pg,
"audit_get_reserves_out_incr",
"SELECT"
@@ -152,8 +150,7 @@ TEH_PG_select_withdrawals_above_serial_id (
",reserve_sig"
",reserves.reserve_pub"
",execution_date"
- ",amount_with_fee_val"
- ",amount_with_fee_frac"
+ ",amount_with_fee"
",reserve_out_serial_id"
" FROM reserves_out"
" JOIN reserves"
@@ -162,8 +159,6 @@ TEH_PG_select_withdrawals_above_serial_id (
" USING (denominations_serial)"
" WHERE reserve_out_serial_id>=$1"
" ORDER BY reserve_out_serial_id ASC;");
-
-
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
"audit_get_reserves_out_incr",
params,
diff --git a/src/exchangedb/pg_select_withdrawals_above_serial_id.h b/src/exchangedb/pg_select_withdrawals_above_serial_id.h
index adc23fb30..2b741a3b4 100644
--- a/src/exchangedb/pg_select_withdrawals_above_serial_id.h
+++ b/src/exchangedb/pg_select_withdrawals_above_serial_id.h
@@ -41,4 +41,5 @@ TEH_PG_select_withdrawals_above_serial_id (
uint64_t serial_id,
TALER_EXCHANGEDB_WithdrawCallback cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_set_extension_manifest.c b/src/exchangedb/pg_set_extension_manifest.c
index 86e9d3f08..c7db04312 100644
--- a/src/exchangedb/pg_set_extension_manifest.c
+++ b/src/exchangedb/pg_set_extension_manifest.c
@@ -28,8 +28,8 @@
enum GNUNET_DB_QueryStatus
TEH_PG_set_extension_manifest (void *cls,
- const char *extension_name,
- const char *manifest)
+ const char *extension_name,
+ const char *manifest)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam pcfg =
diff --git a/src/exchangedb/pg_set_extension_manifest.h b/src/exchangedb/pg_set_extension_manifest.h
index ead3abd28..0befeedd8 100644
--- a/src/exchangedb/pg_set_extension_manifest.h
+++ b/src/exchangedb/pg_set_extension_manifest.h
@@ -37,7 +37,7 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_set_extension_manifest (void *cls,
- const char *extension_name,
+ const char *extension_name,
const char *manifest);
#endif
diff --git a/src/exchangedb/pg_set_purse_balance.c b/src/exchangedb/pg_set_purse_balance.c
index a996104bc..1e34ea6ed 100644
--- a/src/exchangedb/pg_set_purse_balance.c
+++ b/src/exchangedb/pg_set_purse_balance.c
@@ -35,21 +35,18 @@ TEH_PG_set_purse_balance (
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (purse_pub),
- TALER_PQ_query_param_amount (balance),
+ TALER_PQ_query_param_amount (pg->conn,
+ balance),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"set_purse_balance",
"UPDATE purse_requests"
- " SET balance_val=$2"
- " ,balance_frac=$3"
+ " SET balance=$2"
" WHERE purse_pub=$1;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"set_purse_balance",
params);
}
-
-
-
diff --git a/src/exchangedb/pg_setup_wire_target.c b/src/exchangedb/pg_setup_wire_target.c
index a2d890c50..ed6fbe338 100644
--- a/src/exchangedb/pg_setup_wire_target.c
+++ b/src/exchangedb/pg_setup_wire_target.c
@@ -26,7 +26,7 @@
enum GNUNET_DB_QueryStatus
-TEH_PG_setup_wire_target(
+TEH_PG_setup_wire_target (
struct PostgresClosure *pg,
const char *payto_uri,
struct TALER_PaytoHashP *h_payto)
diff --git a/src/exchangedb/pg_setup_wire_target.h b/src/exchangedb/pg_setup_wire_target.h
index 12c0e59b0..77512a600 100644
--- a/src/exchangedb/pg_setup_wire_target.h
+++ b/src/exchangedb/pg_setup_wire_target.h
@@ -35,7 +35,7 @@
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
-TEH_PG_setup_wire_target(
+TEH_PG_setup_wire_target (
struct PostgresClosure *pg,
const char *payto_uri,
struct TALER_PaytoHashP *h_payto);
diff --git a/src/exchangedb/pg_start.c b/src/exchangedb/pg_start.c
index 395b87733..de5d698f6 100644
--- a/src/exchangedb/pg_start.c
+++ b/src/exchangedb/pg_start.c
@@ -28,7 +28,7 @@
enum GNUNET_GenericReturnValue
TEH_PG_start (void *cls,
- const char *name)
+ const char *name)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_ExecuteStatement es[] = {
@@ -54,4 +54,3 @@ TEH_PG_start (void *cls,
pg->transaction_name = name;
return GNUNET_OK;
}
-
diff --git a/src/exchangedb/pg_store_wire_transfer_out.c b/src/exchangedb/pg_store_wire_transfer_out.c
index 8bc0147dd..337dc5855 100644
--- a/src/exchangedb/pg_store_wire_transfer_out.c
+++ b/src/exchangedb/pg_store_wire_transfer_out.c
@@ -40,11 +40,11 @@ TEH_PG_store_wire_transfer_out (
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_string (exchange_account_section),
- TALER_PQ_query_param_amount (amount),
+ TALER_PQ_query_param_amount (pg->conn,
+ amount),
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_store_wire_transfer_out */
PREPARE (pg,
"insert_wire_out",
"INSERT INTO wire_out "
@@ -52,11 +52,9 @@ TEH_PG_store_wire_transfer_out (
",wtid_raw"
",wire_target_h_payto"
",exchange_account_section"
- ",amount_val"
- ",amount_frac"
+ ",amount"
") VALUES "
- "($1, $2, $3, $4, $5, $6);");
-
+ "($1, $2, $3, $4, $5);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"insert_wire_out",
params);
diff --git a/src/exchangedb/pg_template.c b/src/exchangedb/pg_template.c
index 095d89615..69cd45035 100644
--- a/src/exchangedb/pg_template.c
+++ b/src/exchangedb/pg_template.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2024 Taler Systems SA
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
diff --git a/src/exchangedb/pg_template.h b/src/exchangedb/pg_template.h
index 88bb930d3..d858689fb 100644
--- a/src/exchangedb/pg_template.h
+++ b/src/exchangedb/pg_template.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2024 Taler Systems SA
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
diff --git a/src/exchangedb/pg_trigger_aml_process.c b/src/exchangedb/pg_trigger_aml_process.c
index 4dfc8a508..7534fe3df 100644
--- a/src/exchangedb/pg_trigger_aml_process.c
+++ b/src/exchangedb/pg_trigger_aml_process.c
@@ -35,7 +35,8 @@ TEH_PG_trigger_aml_process (
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto),
- TALER_PQ_query_param_amount (threshold_crossed),
+ TALER_PQ_query_param_amount (pg->conn,
+ threshold_crossed),
GNUNET_PQ_query_param_end
};
@@ -43,16 +44,14 @@ TEH_PG_trigger_aml_process (
"trigger_aml_process",
"INSERT INTO aml_status"
"(h_payto"
- ",threshold_val"
- ",threshold_frac"
+ ",threshold"
",status)"
- "VALUES"
- "($1, $2, $3, 1)" // 1: decision needed
- "ON CONFLICT DO"
+ " VALUES"
+ " ($1, $2, 1)" // 1: decision needed
+ " ON CONFLICT (h_payto) DO"
" UPDATE SET"
- " threshold_val=$2"
- " ,threshold_frac=$3"
- " ,status=status | 1;"); // do not clear 'frozen' status
+ " threshold=$2"
+ " ,status=aml_status.status | 1;"); // do not clear 'frozen' status
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"trigger_aml_process",
params);
diff --git a/src/exchangedb/pg_update_aggregation_transient.c b/src/exchangedb/pg_update_aggregation_transient.c
index 1d91301c3..38b65316e 100644
--- a/src/exchangedb/pg_update_aggregation_transient.c
+++ b/src/exchangedb/pg_update_aggregation_transient.c
@@ -26,7 +26,6 @@
#include "pg_helper.h"
-
enum GNUNET_DB_QueryStatus
TEH_PG_update_aggregation_transient (
void *cls,
@@ -37,23 +36,21 @@ TEH_PG_update_aggregation_transient (
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- TALER_PQ_query_param_amount (total),
+ TALER_PQ_query_param_amount (pg->conn,
+ total),
GNUNET_PQ_query_param_auto_from_type (h_payto),
GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_uint64 (&kyc_requirement_row),
GNUNET_PQ_query_param_end
};
-
- /* Used in #postgres_update_aggregation_transient() */
PREPARE (pg,
"update_aggregation_transient",
"UPDATE aggregation_transient"
- " SET amount_val=$1"
- " ,amount_frac=$2"
- " ,legitimization_requirement_serial_id=$5"
- " WHERE wire_target_h_payto=$3"
- " AND wtid_raw=$4");
+ " SET amount=$1"
+ " ,legitimization_requirement_serial_id=$4"
+ " WHERE wire_target_h_payto=$2"
+ " AND wtid_raw=$3");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_aggregation_transient",
params);
diff --git a/src/exchangedb/pg_update_auditor.c b/src/exchangedb/pg_update_auditor.c
index 9d82f25db..167a270b9 100644
--- a/src/exchangedb/pg_update_auditor.c
+++ b/src/exchangedb/pg_update_auditor.c
@@ -28,11 +28,11 @@
enum GNUNET_DB_QueryStatus
TEH_PG_update_auditor (void *cls,
- const struct TALER_AuditorPublicKeyP *auditor_pub,
- const char *auditor_url,
- const char *auditor_name,
- struct GNUNET_TIME_Timestamp change_date,
- bool enabled)
+ const struct TALER_AuditorPublicKeyP *auditor_pub,
+ const char *auditor_url,
+ const char *auditor_name,
+ struct GNUNET_TIME_Timestamp change_date,
+ bool enabled)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -43,16 +43,16 @@ TEH_PG_update_auditor (void *cls,
GNUNET_PQ_query_param_timestamp (&change_date),
GNUNET_PQ_query_param_end
};
- /* used in #postgres_update_auditor() */
- PREPARE(pg,
- "update_auditor",
- "UPDATE auditors"
- " SET"
- " auditor_url=$2"
- " ,auditor_name=$3"
- " ,is_active=$4"
- " ,last_change=$5"
- " WHERE auditor_pub=$1");
+ /* used in #postgres_update_auditor() */
+ PREPARE (pg,
+ "update_auditor",
+ "UPDATE auditors"
+ " SET"
+ " auditor_url=$2"
+ " ,auditor_name=$3"
+ " ,is_active=$4"
+ " ,last_change=$5"
+ " WHERE auditor_pub=$1");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_auditor",
params);
diff --git a/src/exchangedb/pg_update_auditor.h b/src/exchangedb/pg_update_auditor.h
index af8d06062..ee869f8b7 100644
--- a/src/exchangedb/pg_update_auditor.h
+++ b/src/exchangedb/pg_update_auditor.h
@@ -38,10 +38,10 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_update_auditor (void *cls,
- const struct TALER_AuditorPublicKeyP *auditor_pub,
- const char *auditor_url,
- const char *auditor_name,
- struct GNUNET_TIME_Timestamp change_date,
+ const struct TALER_AuditorPublicKeyP *auditor_pub,
+ const char *auditor_url,
+ const char *auditor_name,
+ struct GNUNET_TIME_Timestamp change_date,
bool enabled);
#endif
diff --git a/src/exchangedb/pg_update_kyc_attributes.c b/src/exchangedb/pg_update_kyc_attributes.c
deleted file mode 100644
index f77eb2bfc..000000000
--- a/src/exchangedb/pg_update_kyc_attributes.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file exchangedb/pg_update_kyc_attributes.c
- * @brief Implementation of the update_kyc_attributes function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_update_kyc_attributes.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TEH_PG_update_kyc_attributes (
- void *cls,
- const struct TALER_PaytoHashP *h_payto,
- const struct GNUNET_ShortHashCode *kyc_prox,
- const char *provider_section,
- const char *birthdate,
- struct GNUNET_TIME_Timestamp collection_time,
- struct GNUNET_TIME_Timestamp expiration_time,
- size_t enc_attributes_size,
- const void *enc_attributes)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (h_payto),
- GNUNET_PQ_query_param_auto_from_type (kyc_prox),
- GNUNET_PQ_query_param_string (provider_section),
- (NULL == birthdate)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (birthdate),
- GNUNET_PQ_query_param_timestamp (&collection_time),
- GNUNET_PQ_query_param_timestamp (&expiration_time),
- GNUNET_PQ_query_param_fixed_size (enc_attributes,
- enc_attributes_size),
- GNUNET_PQ_query_param_end
- };
-
- PREPARE (pg,
- "update_kyc_attributes",
- "UPDATE kyc_attributes SET "
- " kyc_prox=$2"
- ",birthdate=$4"
- ",collection_time=$5"
- ",expiration_time=$6"
- ",encrypted_attributes=$7"
- " WHERE h_payto=$1 AND provider_section=$3;");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_kyc_attributes",
- params);
-}
diff --git a/src/exchangedb/pg_update_kyc_process_by_row.c b/src/exchangedb/pg_update_kyc_process_by_row.c
index 4ae44ce53..c339436a8 100644
--- a/src/exchangedb/pg_update_kyc_process_by_row.c
+++ b/src/exchangedb/pg_update_kyc_process_by_row.c
@@ -25,6 +25,7 @@
#include "pg_update_kyc_process_by_row.h"
#include "pg_helper.h"
+
enum GNUNET_DB_QueryStatus
TEH_PG_update_kyc_process_by_row (
void *cls,
@@ -33,6 +34,7 @@ TEH_PG_update_kyc_process_by_row (
const struct TALER_PaytoHashP *h_payto,
const char *provider_account_id,
const char *provider_legitimization_id,
+ const char *redirect_url,
struct GNUNET_TIME_Absolute expiration)
{
struct PostgresClosure *pg = cls;
@@ -46,17 +48,25 @@ TEH_PG_update_kyc_process_by_row (
(NULL != provider_legitimization_id)
? GNUNET_PQ_query_param_string (provider_legitimization_id)
: GNUNET_PQ_query_param_null (),
+ (NULL != redirect_url)
+ ? GNUNET_PQ_query_param_string (redirect_url)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_absolute_time (&expiration),
GNUNET_PQ_query_param_end
};
enum GNUNET_DB_QueryStatus qs;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Updating KYC data for %llu (%s)\n",
+ (unsigned long long) process_row,
+ provider_section);
PREPARE (pg,
"update_legitimization_process",
"UPDATE legitimization_processes"
" SET provider_user_id=$4"
" ,provider_legitimization_id=$5"
- " ,expiration_time=GREATEST(expiration_time,$6)"
+ " ,redirect_url=$6"
+ " ,expiration_time=GREATEST(expiration_time,$7)"
" WHERE"
" h_payto=$3"
" AND legitimization_process_serial_id=$1"
@@ -68,7 +78,8 @@ TEH_PG_update_kyc_process_by_row (
if (qs <= 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to update legitimization process: %d\n",
+ "Failed to update legitimization process %llu: %d\n",
+ (unsigned long long) process_row,
qs);
return qs;
}
diff --git a/src/exchangedb/pg_update_kyc_process_by_row.h b/src/exchangedb/pg_update_kyc_process_by_row.h
index 07e896dbc..7ef5285e9 100644
--- a/src/exchangedb/pg_update_kyc_process_by_row.h
+++ b/src/exchangedb/pg_update_kyc_process_by_row.h
@@ -35,6 +35,7 @@
* @param h_payto account that must be KYC'ed (helps access by shard, otherwise also redundant)
* @param provider_account_id provider account ID
* @param provider_legitimization_id provider legitimization ID
+ * @param redirect_url where the user should be redirected to start the KYC process
* @param expiration how long is this KYC check set to be valid (in the past if invalid)
* @return database transaction status
*/
@@ -46,6 +47,7 @@ TEH_PG_update_kyc_process_by_row (
const struct TALER_PaytoHashP *h_payto,
const char *provider_account_id,
const char *provider_legitimization_id,
+ const char *redirect_url,
struct GNUNET_TIME_Absolute expiration);
#endif
diff --git a/src/exchangedb/pg_update_wire.c b/src/exchangedb/pg_update_wire.c
index f5f5672cb..5c4bb9045 100644
--- a/src/exchangedb/pg_update_wire.c
+++ b/src/exchangedb/pg_update_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023, 2024 Taler Systems SA
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
@@ -28,25 +28,52 @@
enum GNUNET_DB_QueryStatus
TEH_PG_update_wire (void *cls,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp change_date,
- bool enabled)
+ const char *payto_uri,
+ const char *conversion_url,
+ const json_t *debit_restrictions,
+ const json_t *credit_restrictions,
+ struct GNUNET_TIME_Timestamp change_date,
+ const struct TALER_MasterSignatureP *master_sig,
+ const char *bank_label,
+ int64_t priority,
+ bool enabled)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_bool (enabled),
+ NULL == conversion_url
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (conversion_url),
+ enabled
+ ? TALER_PQ_query_param_json (debit_restrictions)
+ : GNUNET_PQ_query_param_null (),
+ enabled
+ ? TALER_PQ_query_param_json (credit_restrictions)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_timestamp (&change_date),
+ NULL == master_sig
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_auto_from_type (master_sig),
+ NULL == bank_label
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (bank_label),
+ GNUNET_PQ_query_param_int64 (&priority),
GNUNET_PQ_query_param_end
};
- /* used in #postgres_update_wire() */
PREPARE (pg,
"update_wire",
"UPDATE wire_accounts"
" SET"
" is_active=$2"
- " ,last_change=$3"
+ " ,conversion_url=$3"
+ " ,debit_restrictions=$4"
+ " ,credit_restrictions=$5"
+ " ,last_change=$6"
+ " ,master_sig=$7"
+ " ,bank_label=$8"
+ " ,priority=$9"
" WHERE payto_uri=$1");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_wire",
diff --git a/src/exchangedb/pg_update_wire.h b/src/exchangedb/pg_update_wire.h
index c01d68a46..a596a0802 100644
--- a/src/exchangedb/pg_update_wire.h
+++ b/src/exchangedb/pg_update_wire.h
@@ -24,20 +24,34 @@
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
+
+
/**
* Update information about a wire account of the exchange.
*
* @param cls closure
* @param payto_uri account the update is about
+ * @param conversion_url URL of a conversion service, NULL if there is no conversion
+ * @param debit_restrictions JSON array with debit restrictions on the account; NULL allowed if not @a enabled
+ * @param credit_restrictions JSON array with credit restrictions on the account; NULL allowed if not @a enabled
* @param change_date date when the account status was last changed
* (only to be used for replay detection)
+ * @param master_sig master signature to store, can be NULL (if @a enabled is false)
+ * @param bank_label label to show this entry under in the UI, can be NULL
+ * @param priority determines order in which entries are shown in the UI
* @param enabled true to enable, false to disable (the actual change)
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
TEH_PG_update_wire (void *cls,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp change_date,
+ const char *payto_uri,
+ const char *conversion_url,
+ const json_t *debit_restrictions,
+ const json_t *credit_restrictions,
+ struct GNUNET_TIME_Timestamp change_date,
+ const struct TALER_MasterSignatureP *master_sig,
+ const char *bank_label,
+ int64_t priority,
bool enabled);
#endif
diff --git a/src/exchangedb/pg_wire_prepare_data_get.c b/src/exchangedb/pg_wire_prepare_data_get.c
index d45413010..0cc57e41f 100644
--- a/src/exchangedb/pg_wire_prepare_data_get.c
+++ b/src/exchangedb/pg_wire_prepare_data_get.c
@@ -99,10 +99,10 @@ prewire_cb (void *cls,
enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_get (void *cls,
- uint64_t start_row,
- uint64_t limit,
- TALER_EXCHANGEDB_WirePreparationIterator cb,
- void *cb_cls)
+ uint64_t start_row,
+ uint64_t limit,
+ TALER_EXCHANGEDB_WirePreparationIterator cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -117,8 +117,6 @@ TEH_PG_wire_prepare_data_get (void *cls,
};
enum GNUNET_DB_QueryStatus qs;
-
- /* Used in #postgres_wire_prepare_data_get() */
PREPARE (pg,
"wire_prepare_data_get",
"SELECT"
diff --git a/src/exchangedb/pg_wire_prepare_data_get.h b/src/exchangedb/pg_wire_prepare_data_get.h
index 91e21d27e..815c14bdf 100644
--- a/src/exchangedb/pg_wire_prepare_data_get.h
+++ b/src/exchangedb/pg_wire_prepare_data_get.h
@@ -38,8 +38,9 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_get (void *cls,
- uint64_t start_row,
- uint64_t limit,
- TALER_EXCHANGEDB_WirePreparationIterator cb,
+ uint64_t start_row,
+ uint64_t limit,
+ TALER_EXCHANGEDB_WirePreparationIterator cb,
void *cb_cls);
+
#endif
diff --git a/src/exchangedb/pg_wire_prepare_data_insert.c b/src/exchangedb/pg_wire_prepare_data_insert.c
index 903f22a5b..919fccdaf 100644
--- a/src/exchangedb/pg_wire_prepare_data_insert.c
+++ b/src/exchangedb/pg_wire_prepare_data_insert.c
@@ -27,9 +27,9 @@
enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_insert (void *cls,
- const char *type,
- const char *buf,
- size_t buf_size)
+ const char *type,
+ const char *buf,
+ size_t buf_size)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -39,15 +39,15 @@ TEH_PG_wire_prepare_data_insert (void *cls,
};
- /* Used in #postgres_wire_prepare_data_insert() to store
- wire transfer information before actually committing it with the bank */
+ /* Used in #postgres_wire_prepare_data_insert() to store
+ wire transfer information before actually committing it with the bank */
PREPARE (pg,
- "wire_prepare_data_insert",
- "INSERT INTO prewire "
- "(wire_method"
- ",buf"
- ") VALUES "
- "($1, $2);");
+ "wire_prepare_data_insert",
+ "INSERT INTO prewire "
+ "(wire_method"
+ ",buf"
+ ") VALUES "
+ "($1, $2);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"wire_prepare_data_insert",
params);
diff --git a/src/exchangedb/pg_wire_prepare_data_insert.h b/src/exchangedb/pg_wire_prepare_data_insert.h
index 2b6050d05..e73ee152d 100644
--- a/src/exchangedb/pg_wire_prepare_data_insert.h
+++ b/src/exchangedb/pg_wire_prepare_data_insert.h
@@ -36,7 +36,8 @@
*/
enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_insert (void *cls,
- const char *type,
- const char *buf,
+ const char *type,
+ const char *buf,
size_t buf_size);
+
#endif
diff --git a/src/exchangedb/pg_wire_prepare_data_mark_failed.c b/src/exchangedb/pg_wire_prepare_data_mark_failed.c
index fe2236b82..1d46c84d4 100644
--- a/src/exchangedb/pg_wire_prepare_data_mark_failed.c
+++ b/src/exchangedb/pg_wire_prepare_data_mark_failed.c
@@ -37,8 +37,6 @@ TEH_PG_wire_prepare_data_mark_failed (
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_wire_prepare_data_mark_failed() */
-
PREPARE (pg,
"wire_prepare_data_mark_failed",
"UPDATE prewire"
diff --git a/src/exchangedb/pg_wire_prepare_data_mark_failed.h b/src/exchangedb/pg_wire_prepare_data_mark_failed.h
index cae1523d1..98846b284 100644
--- a/src/exchangedb/pg_wire_prepare_data_mark_failed.h
+++ b/src/exchangedb/pg_wire_prepare_data_mark_failed.h
@@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_mark_failed (
void *cls,
uint64_t rowid);
+
#endif
diff --git a/src/exchangedb/pg_wire_prepare_data_mark_finished.c b/src/exchangedb/pg_wire_prepare_data_mark_finished.c
index de8738e40..998b9d731 100644
--- a/src/exchangedb/pg_wire_prepare_data_mark_finished.c
+++ b/src/exchangedb/pg_wire_prepare_data_mark_finished.c
@@ -36,13 +36,11 @@ TEH_PG_wire_prepare_data_mark_finished (
GNUNET_PQ_query_param_end
};
- /* Used in #postgres_wire_prepare_data_mark_finished() */
PREPARE (pg,
- "wire_prepare_data_mark_done",
- "UPDATE prewire"
- " SET finished=TRUE"
- " WHERE prewire_uuid=$1;");
-
+ "wire_prepare_data_mark_done",
+ "UPDATE prewire"
+ " SET finished=TRUE"
+ " WHERE prewire_uuid=$1;");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"wire_prepare_data_mark_done",
params);
diff --git a/src/exchangedb/pg_wire_prepare_data_mark_finished.h b/src/exchangedb/pg_wire_prepare_data_mark_finished.h
index 19db2ca99..ba2e384cd 100644
--- a/src/exchangedb/pg_wire_prepare_data_mark_finished.h
+++ b/src/exchangedb/pg_wire_prepare_data_mark_finished.h
@@ -36,4 +36,5 @@ enum GNUNET_DB_QueryStatus
TEH_PG_wire_prepare_data_mark_finished (
void *cls,
uint64_t rowid);
+
#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index b201ef554..108b55219 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014--2022 Taler Systems SA
+ Copyright (C) 2014--2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -21,6 +21,7 @@
* @author Christian Grothoff
* @author Sree Harsha Totakura
* @author Marcello Stanisci
+ * @author Özgür Kesim
*/
#include "platform.h"
#include <poll.h>
@@ -37,7 +38,6 @@
#include "pg_get_link_data.h"
#include "pg_helper.h"
#include "pg_do_reserve_open.h"
-#include "pg_do_withdraw.h"
#include "pg_get_coin_transactions.h"
#include "pg_get_expired_reserves.h"
#include "pg_get_purse_request.h"
@@ -46,11 +46,13 @@
#include "pg_insert_close_request.h"
#include "pg_insert_records_by_table.h"
#include "pg_insert_reserve_open_deposit.h"
+#include "pg_get_pending_kyc_requirement_process.h"
#include "pg_iterate_kyc_reference.h"
#include "pg_iterate_reserve_close_info.h"
#include "pg_lookup_records_by_table.h"
#include "pg_lookup_serial_by_table.h"
#include "pg_select_account_merges_above_serial_id.h"
+#include "pg_select_aml_threshold.h"
#include "pg_select_all_purse_decisions_above_serial_id.h"
#include "pg_select_purse.h"
#include "pg_select_purse_deposits_above_serial_id.h"
@@ -63,7 +65,6 @@
#include "pg_iterate_active_signkeys.h"
#include "pg_preflight.h"
#include "pg_commit.h"
-#include "pg_insert_aggregation_tracking.h"
#include "pg_drop_tables.h"
#include "pg_select_satisfied_kyc_processes.h"
#include "pg_select_aggregation_amounts_for_kyc_check.h"
@@ -80,6 +81,7 @@
#include "pg_get_drain_profit.h"
#include "pg_get_purse_deposit.h"
#include "pg_insert_contract.h"
+#include "pg_insert_kyc_failure.h"
#include "pg_select_contract.h"
#include "pg_select_purse_merge.h"
#include "pg_select_contract_by_purse.h"
@@ -91,7 +93,6 @@
#include "pg_update_auditor.h"
#include "pg_begin_revolving_shard.h"
#include "pg_get_extension_manifest.h"
-#include "pg_insert_history_request.h"
#include "pg_do_purse_delete.h"
#include "pg_do_purse_merge.h"
#include "pg_start_read_committed.h"
@@ -115,10 +116,13 @@
#include "pg_drain_kyc_alert.h"
#include "pg_reserves_in_insert.h"
#include "pg_get_withdraw_info.h"
+#include "pg_get_age_withdraw.h"
#include "pg_do_batch_withdraw.h"
+#include "pg_do_age_withdraw.h"
#include "pg_get_policy_details.h"
#include "pg_persist_policy_details.h"
#include "pg_do_deposit.h"
+#include "pg_get_wire_hash_for_contract.h"
#include "pg_add_policy_fulfillment_proof.h"
#include "pg_do_melt.h"
#include "pg_do_refund.h"
@@ -128,6 +132,7 @@
#include "pg_count_known_coins.h"
#include "pg_ensure_coin_known.h"
#include "pg_get_known_coin.h"
+#include "pg_get_signature_for_known_coin.h"
#include "pg_get_coin_denomination.h"
#include "pg_have_deposit2.h"
#include "pg_aggregate.h"
@@ -136,7 +141,6 @@
#include "pg_find_aggregation_transient.h"
#include "pg_update_aggregation_transient.h"
#include "pg_get_ready_deposit.h"
-#include "pg_insert_deposit.h"
#include "pg_insert_refund.h"
#include "pg_select_refunds_by_coin.h"
#include "pg_get_melt.h"
@@ -157,8 +161,8 @@
#include "pg_start_deferred_wire_out.h"
#include "pg_store_wire_transfer_out.h"
#include "pg_gc.h"
-#include "pg_select_deposits_above_serial_id.h"
-#include "pg_select_history_requests_above_serial_id.h"
+#include "pg_inject_auditor_triggers.h"
+#include "pg_select_coin_deposits_above_serial_id.h"
#include "pg_select_purse_decisions_above_serial_id.h"
#include "pg_select_purse_deposits_by_purse.h"
#include "pg_select_refreshes_above_serial_id.h"
@@ -174,7 +178,9 @@
#include "pg_get_old_coin_by_h_blind.h"
#include "pg_insert_denomination_revocation.h"
#include "pg_get_denomination_revocation.h"
-#include "pg_select_deposits_missing_wire.h"
+#include "pg_select_batch_deposits_missing_wire.h"
+#include "pg_select_justification_for_missing_wire.h"
+#include "pg_select_aggregations_above_serial.h"
#include "pg_lookup_auditor_timestamp.h"
#include "pg_lookup_auditor_status.h"
#include "pg_insert_auditor.h"
@@ -204,7 +210,6 @@
#include "pg_setup_wire_target.h"
#include "pg_compute_shard.h"
#include "pg_insert_kyc_attributes.h"
-#include "pg_update_kyc_attributes.h"
#include "pg_select_similar_kyc_attributes.h"
#include "pg_select_kyc_attributes.h"
#include "pg_insert_aml_officer.h"
@@ -214,14 +219,14 @@
#include "pg_select_aml_process.h"
#include "pg_select_aml_history.h"
#include "pg_insert_aml_decision.h"
-
+#include "pg_batch_ensure_coin_known.h"
/**
* Set to 1 to enable Postgres auto_explain module. This will
* slow down things a _lot_, but also provide extensive logging
* in the Postgres database logger for performance analysis.
*/
-#define AUTO_EXPLAIN 1
+#define AUTO_EXPLAIN 0
/**
@@ -268,6 +273,8 @@ TEH_PG_internal_setup (struct PostgresClosure *pg)
GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
+ /* Mergejoin causes issues, see Postgres #18380 */
+ GNUNET_PQ_make_try_execute ("SET enable_mergejoin=OFF;"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
#else
@@ -276,7 +283,8 @@ TEH_PG_internal_setup (struct PostgresClosure *pg)
"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
- GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"),
+ /* Mergejoin causes issues, see Postgres #18380 */
+ GNUNET_PQ_make_try_execute ("SET enable_mergejoin=OFF;"),
GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
@@ -290,6 +298,7 @@ TEH_PG_internal_setup (struct PostgresClosure *pg)
NULL);
if (NULL == db_conn)
return GNUNET_SYSERR;
+
pg->prep_gen++;
pg->conn = db_conn;
}
@@ -341,21 +350,29 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
GNUNET_free (pg);
return NULL;
}
- if ( (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (cfg,
- "exchangedb",
- "IDLE_RESERVE_EXPIRATION_TIME",
- &pg->idle_reserve_expiration_time))
- ||
- (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (cfg,
- "exchangedb",
- "LEGAL_RESERVE_EXPIRATION_TIME",
- &pg->legal_reserve_expiration_time)) )
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ "exchangedb",
+ "IDLE_RESERVE_EXPIRATION_TIME",
+ &pg->idle_reserve_expiration_time))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchangedb",
+ "IDLE_RESERVE_EXPIRATION_TIME");
+ GNUNET_free (pg->exchange_url);
+ GNUNET_free (pg->sql_dir);
+ GNUNET_free (pg);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ "exchangedb",
+ "LEGAL_RESERVE_EXPIRATION_TIME",
+ &pg->legal_reserve_expiration_time))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchangedb",
- "LEGAL/IDLE_RESERVE_EXPIRATION_TIME");
+ "LEGAL_RESERVE_EXPIRATION_TIME");
GNUNET_free (pg->exchange_url);
GNUNET_free (pg->sql_dir);
GNUNET_free (pg);
@@ -411,8 +428,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_do_reserve_open;
plugin->drop_tables
= &TEH_PG_drop_tables;
- plugin->do_withdraw
- = &TEH_PG_do_withdraw;
plugin->free_coin_transaction_list
= &TEH_COMMON_free_coin_transaction_list;
plugin->free_reserve_history
@@ -425,8 +440,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_get_purse_request;
plugin->get_reserve_history
= &TEH_PG_get_reserve_history;
- plugin->get_reserve_status
- = &TEH_PG_get_reserve_status;
plugin->get_unfinished_close_requests
= &TEH_PG_get_unfinished_close_requests;
plugin->insert_records_by_table
@@ -451,6 +464,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_account_merges_above_serial_id;
plugin->select_all_purse_decisions_above_serial_id
= &TEH_PG_select_all_purse_decisions_above_serial_id;
+ plugin->select_aml_threshold
+ = &TEH_PG_select_aml_threshold;
plugin->select_purse
= &TEH_PG_select_purse;
plugin->select_purse_deposits_above_serial_id
@@ -473,8 +488,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_commit;
plugin->preflight
= &TEH_PG_preflight;
- plugin->insert_aggregation_tracking
- = &TEH_PG_insert_aggregation_tracking;
plugin->select_aggregation_amounts_for_kyc_check
= &TEH_PG_select_aggregation_amounts_for_kyc_check;
plugin->select_satisfied_kyc_processes
@@ -527,8 +540,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_begin_revolving_shard;
plugin->get_extension_manifest
= &TEH_PG_get_extension_manifest;
- plugin->insert_history_request
- = &TEH_PG_insert_history_request;
plugin->do_purse_merge
= &TEH_PG_do_purse_merge;
plugin->do_purse_delete
@@ -577,12 +588,18 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_get_withdraw_info;
plugin->do_batch_withdraw
= &TEH_PG_do_batch_withdraw;
+ plugin->do_age_withdraw
+ = &TEH_PG_do_age_withdraw;
+ plugin->get_age_withdraw
+ = &TEH_PG_get_age_withdraw;
plugin->get_policy_details
= &TEH_PG_get_policy_details;
plugin->persist_policy_details
= &TEH_PG_persist_policy_details;
plugin->do_deposit
= &TEH_PG_do_deposit;
+ plugin->get_wire_hash_for_contract
+ = &TEH_PG_get_wire_hash_for_contract;
plugin->add_policy_fulfillment_proof
= &TEH_PG_add_policy_fulfillment_proof;
plugin->do_melt
@@ -601,6 +618,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_ensure_coin_known;
plugin->get_known_coin
= &TEH_PG_get_known_coin;
+ plugin->get_signature_for_known_coin
+ = &TEH_PG_get_signature_for_known_coin;
plugin->get_coin_denomination
= &TEH_PG_get_coin_denomination;
plugin->have_deposit2
@@ -617,8 +636,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_update_aggregation_transient;
plugin->get_ready_deposit
= &TEH_PG_get_ready_deposit;
- plugin->insert_deposit
- = &TEH_PG_insert_deposit;
plugin->insert_refund
= &TEH_PG_insert_refund;
plugin->select_refunds_by_coin
@@ -659,10 +676,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_store_wire_transfer_out;
plugin->gc
= &TEH_PG_gc;
- plugin->select_deposits_above_serial_id
- = &TEH_PG_select_deposits_above_serial_id;
- plugin->select_history_requests_above_serial_id
- = &TEH_PG_select_history_requests_above_serial_id;
+ plugin->select_coin_deposits_above_serial_id
+ = &TEH_PG_select_coin_deposits_above_serial_id;
plugin->select_purse_decisions_above_serial_id
= &TEH_PG_select_purse_decisions_above_serial_id;
plugin->select_purse_deposits_by_purse
@@ -693,8 +708,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_insert_denomination_revocation;
plugin->get_denomination_revocation
= &TEH_PG_get_denomination_revocation;
- plugin->select_deposits_missing_wire
- = &TEH_PG_select_deposits_missing_wire;
+ plugin->select_batch_deposits_missing_wire
+ = &TEH_PG_select_batch_deposits_missing_wire;
+ plugin->select_justification_for_missing_wire
+ = &TEH_PG_select_justification_for_missing_wire;
+ plugin->select_aggregations_above_serial
+ = &TEH_PG_select_aggregations_above_serial;
plugin->lookup_auditor_timestamp
= &TEH_PG_lookup_auditor_timestamp;
plugin->lookup_auditor_status
@@ -729,6 +748,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_begin_shard;
plugin->abort_shard
= &TEH_PG_abort_shard;
+ plugin->insert_kyc_failure
+ = &TEH_PG_insert_kyc_failure;
plugin->complete_shard
= &TEH_PG_complete_shard;
plugin->release_revolving_shard
@@ -745,10 +766,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_purse_by_merge_pub;
plugin->set_purse_balance
= &TEH_PG_set_purse_balance;
+ plugin->get_pending_kyc_requirement_process
+ = &TEH_PG_get_pending_kyc_requirement_process;
plugin->insert_kyc_attributes
= &TEH_PG_insert_kyc_attributes;
- plugin->update_kyc_attributes
- = &TEH_PG_update_kyc_attributes;
plugin->select_similar_kyc_attributes
= &TEH_PG_select_similar_kyc_attributes;
plugin->select_kyc_attributes
@@ -767,6 +788,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_aml_history;
plugin->insert_aml_decision
= &TEH_PG_insert_aml_decision;
+
+ plugin->batch_ensure_coin_known
+ = &TEH_PG_batch_ensure_coin_known;
+ plugin->inject_auditor_triggers
+ = &TEH_PG_inject_auditor_triggers;
+
return plugin;
}
diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in
index a53396c36..7afb01f0b 100644
--- a/src/exchangedb/procedures.sql.in
+++ b/src/exchangedb/procedures.sql.in
@@ -18,12 +18,14 @@ BEGIN;
SET search_path TO exchange;
-#include "exchange_do_withdraw.sql"
+#include "exchange_do_amount_specific.sql"
#include "exchange_do_batch_withdraw.sql"
#include "exchange_do_batch_withdraw_insert.sql"
-#include "exchange_do_recoup_by_reserve.sql"
+#include "exchange_do_age_withdraw.sql"
#include "exchange_do_deposit.sql"
#include "exchange_do_melt.sql"
+#include "exchange_do_select_deposits_missing_wire.sql"
+#include "exchange_do_select_justification_for_missing_wire.sql"
#include "exchange_do_refund.sql"
#include "exchange_do_recoup_to_reserve.sql"
#include "exchange_do_recoup_to_coin.sql"
@@ -33,19 +35,15 @@ SET search_path TO exchange;
#include "exchange_do_purse_merge.sql"
#include "exchange_do_reserve_purse.sql"
#include "exchange_do_expire_purse.sql"
-#include "exchange_do_history_request.sql"
#include "exchange_do_reserve_open_deposit.sql"
#include "exchange_do_reserve_open.sql"
#include "exchange_do_insert_or_update_policy_details.sql"
#include "exchange_do_insert_aml_decision.sql"
#include "exchange_do_insert_aml_officer.sql"
-#include "exchange_do_batch_reserves_in_insert.sql"
+#include "exchange_do_insert_kyc_attributes.sql"
+#include "exchange_do_reserves_in_insert.sql"
#include "exchange_do_batch_reserves_update.sql"
-#include "exchange_do_batch2_reserves_in_insert.sql"
-#include "exchange_do_batch4_reserves_in_insert.sql"
-#include "exchange_do_batch8_reserves_in_insert.sql"
-#include "exchange_do_refund_by_coin.sql"
-#include "exchange_do_get_ready_deposit.sql"
#include "exchange_do_get_link_data.sql"
+#include "exchange_do_batch_coin_known.sql"
COMMIT;
diff --git a/src/exchangedb/spi/Makefile b/src/exchangedb/spi/Makefile
new file mode 100644
index 000000000..d654d91e9
--- /dev/null
+++ b/src/exchangedb/spi/Makefile
@@ -0,0 +1,9 @@
+EXTENSION = own_test
+MODULES = own_test
+DATA = own_test.sql
+PG_CPPFLAGS = -I /usr/include/postgresql
+
+# postgresql build stuff
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
diff --git a/src/exchangedb/spi/README.md b/src/exchangedb/spi/README.md
new file mode 100644
index 000000000..47eb37b94
--- /dev/null
+++ b/src/exchangedb/spi/README.md
@@ -0,0 +1,37 @@
+ Server Programming Interface (SPI)
+
+
+Overview
+========
+
+This folder contains results from an experiment by Joseph Xu
+to use the Postgres SPI. They are not currently used at all
+by the GNU Taler exchange.
+
+
+Dependencies
+============
+
+These are the direct dependencies for compiling the code:
+
+# apt-get install libpq-dev postgresql-server-dev-13
+# apt-get install libkrb5-dev
+# apt-get install libssl-dev
+
+
+Compilation
+===========
+
+$ make
+
+Loading functions
+=================
+
+# make install
+$ psql "$DB_NAME" < own_test.sql
+
+
+Calling functions
+==================
+
+$ psql -c "SELECT $FUNCTION_NAME($ARGS);" "$DB_NAME"
diff --git a/src/exchangedb/spi/own_test.c b/src/exchangedb/spi/own_test.c
new file mode 100644
index 000000000..ac72fad7b
--- /dev/null
+++ b/src/exchangedb/spi/own_test.c
@@ -0,0 +1,873 @@
+#include "postgres.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <postgresql/libpq-fe.h>
+#include <libpq-int.h>
+#include <catalog/pg_type.h>
+#include <executor/spi.h>
+#include <funcapi.h>
+#include <fmgr.h>
+#include <utils/builtins.h>
+#include <utils/array.h>
+#include <sys/time.h>
+#include <utils/numeric.h>
+#include <utils/timestamp.h>
+#include <utils/bytea.h>
+
+#ifdef PG_MODULE_MAGIC
+PG_MODULE_MAGIC;
+#endif
+
+typedef struct
+{
+ Datum col1;
+ Datum col2;
+} valuest;
+
+void _PG_init (void);
+
+void _PG_fini (void);
+
+void
+_PG_init (void)
+{
+}
+
+
+PG_FUNCTION_INFO_V1 (pg_spi_insert_int);
+PG_FUNCTION_INFO_V1 (pg_spi_select_from_x);
+PG_FUNCTION_INFO_V1 (pg_spi_select_pair_from_y);
+// PG_FUNCTION_INFO_V1(pg_spi_select_with_cond);
+PG_FUNCTION_INFO_V1 (pg_spi_update_y);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_example);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_example_without_saveplan);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_insert);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_insert_without_saveplan);
+// PG_FUNCTION_INFO_V1(pg_spi_prepare_select_with_cond);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_select_with_cond_without_saveplan);
+PG_FUNCTION_INFO_V1 (pg_spi_prepare_update);
+PG_FUNCTION_INFO_V1 (pg_spi_get_dep_ref_fees);
+// SIMPLE SELECT
+Datum
+pg_spi_prepare_example (PG_FUNCTION_ARGS)
+{
+ static SPIPlanPtr prepared_plan;
+ int ret;
+ int64 result;
+ char *value;
+ SPIPlanPtr new_plan;
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "DB connection failed ! \n");
+ }
+ {
+ if (prepared_plan == NULL)
+ {
+ new_plan = SPI_prepare ("SELECT 1 FROM X", 0, NULL);
+ prepared_plan = SPI_saveplan (new_plan);
+
+ if (prepared_plan == NULL)
+ {
+ elog (ERROR, "FAIL TO SAVE !\n");
+ }
+ }
+
+ ret = SPI_execute_plan (prepared_plan, NULL, 0,false, 0);
+ if (ret != SPI_OK_SELECT)
+ {
+ elog (ERROR, "SELECT FAILED %d !\n", ret);
+ }
+
+ if (SPI_tuptable != NULL && SPI_tuptable->vals != NULL &&
+ SPI_tuptable->tupdesc != NULL)
+ {
+ value = SPI_getvalue (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
+ result = atoi (value);
+ }
+ else
+ {
+ elog (ERROR, "EMPTY TABLE !\n");
+ }
+ }
+ SPI_finish ();
+ PG_RETURN_INT64 (result);
+}
+
+
+Datum
+pg_spi_prepare_example_without_saveplan (PG_FUNCTION_ARGS)
+{
+ int ret;
+ int64 result;
+ char *value;
+ SPIPlanPtr new_plan;
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "DB connection failed ! \n");
+ }
+
+ {
+ new_plan = SPI_prepare ("SELECT 1 FROM X", 0, NULL);
+ ret = SPI_execute_plan (new_plan, NULL, 0,false, 0);
+ if (ret != SPI_OK_SELECT)
+ {
+ elog (ERROR, "SELECT FAILED %d !\n", ret);
+ }
+
+ if (SPI_tuptable != NULL
+ && SPI_tuptable->vals != NULL
+ && SPI_tuptable->tupdesc != NULL)
+ {
+ value = SPI_getvalue (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
+ result = atoi (value);
+ }
+ else
+ {
+ elog (ERROR, "EMPTY TABLE !\n");
+ }
+ }
+ SPI_finish ();
+ PG_RETURN_INT64 (result);// PG_RETURN_INT64(result);
+}
+
+
+// SELECT 1 FROM X
+// V1
+Datum
+pg_spi_select_from_x (PG_FUNCTION_ARGS)
+{
+ int ret;
+ char *query = "SELECT 1 FROM X";
+ uint64 proc;
+ ret = SPI_connect ();
+
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed");
+ }
+
+ ret = SPI_exec (query, 10);
+ proc = SPI_processed;
+ if (ret != SPI_OK_SELECT)
+ {
+ elog (ERROR, "SPI_exec failed");
+ }
+
+ SPI_finish ();
+
+ PG_RETURN_INT64 (proc);
+}
+
+
+// INSERT INTO X VALUES (1)
+Datum
+pg_spi_insert_int (PG_FUNCTION_ARGS)
+{
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ char *query = "INSERT INTO X (a) VALUES ($1)";
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed");
+ }
+
+ nargs = 1;
+ argtypes[0] = INT4OID;
+ values[0] = Int32GetDatum (3);
+
+ ret = SPI_execute_with_args (query, nargs, argtypes, values, NULL, false, 0);
+ if (ret != SPI_OK_INSERT)
+ {
+ elog (ERROR, "SPI_execute_with_args failed");
+ }
+
+ SPI_finish ();
+
+ PG_RETURN_VOID ();
+}
+
+
+Datum
+pg_spi_prepare_insert (PG_FUNCTION_ARGS)
+{
+ static SPIPlanPtr prepared_plan = NULL;
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ const char *query = "INSERT INTO X (a) VALUES ($1)";
+ SPIPlanPtr new_plan;
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed ! \n");
+ }
+ if (prepared_plan == NULL)
+ {
+
+ argtypes[0] = INT4OID;
+ nargs = 1;
+ values[0] = Int32GetDatum (3);
+ new_plan = SPI_prepare (query, nargs, argtypes);
+ if (new_plan== NULL)
+ {
+ elog (ERROR, "SPI_prepare failed ! \n");
+ }
+ prepared_plan = SPI_saveplan (new_plan);
+ if (prepared_plan == NULL)
+ {
+ elog (ERROR, "SPI_saveplan failed ! \n");
+ }
+ }
+
+ ret = SPI_execute_plan (prepared_plan, values, NULL, false, 0);
+ if (ret != SPI_OK_INSERT)
+ {
+ elog (ERROR, "SPI_execute_plan failed ! \n");
+ }
+
+ SPI_finish ();
+
+ PG_RETURN_VOID ();
+}
+
+
+/*
+Datum
+pg_spi_prepare_insert_bytea(PG_FUNCTION_ARGS)
+{
+ static SPIPlanPtr prepared_plan = NULL;
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ Oid argtypes2[1];
+ Datum val[1];
+ char *query = "INSERT INTO X (a) VALUES ($1)";
+ SPIPlanPtr new_plan;
+ ret = SPI_connect();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog(ERROR, "SPI_connect failed ! \n");
+ }
+ if (prepared_plan == NULL) {
+ argtypes2[0] = BOOLOID;
+ val[0] = BoolGetDatum();
+ argtypes[0] = BYTEAOID;
+ nargs = 1;
+ values[0] = Int32GetDatum(3);
+ new_plan = SPI_prepare(query, nargs, argtypes);
+ if (new_plan== NULL)
+ {
+ elog(ERROR, "SPI_prepare failed ! \n");
+ }
+ prepared_plan = SPI_saveplan(new_plan);
+ if (prepared_plan == NULL)
+ {
+ elog(ERROR, "SPI_saveplan failed ! \n");
+ }
+ }
+
+ ret = SPI_execute_plan(prepared_plan, values, NULL, false, 0);
+ if (ret != SPI_OK_INSERT)
+ {
+ elog(ERROR, "SPI_execute_plan failed ! \n");
+ }
+
+ SPI_finish();
+
+ PG_RETURN_VOID();
+}
+*/
+
+Datum
+pg_spi_prepare_insert_without_saveplan (PG_FUNCTION_ARGS)
+{
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ const char *query = "INSERT INTO X (a) VALUES ($1)";
+ SPIPlanPtr new_plan;
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed");
+ }
+ {
+ argtypes[0] = INT4OID;
+ nargs = 1;
+ values[0] = Int32GetDatum (3);
+ new_plan = SPI_prepare (query, nargs, argtypes);
+ if (new_plan== NULL)
+ {
+ elog (ERROR, "SPI_prepare failed");
+ }
+ }
+
+ ret = SPI_execute_plan (new_plan, values, NULL, false, 0);
+ if (ret != SPI_OK_INSERT)
+ {
+ elog (ERROR, "SPI_execute_plan failed");
+ }
+
+ SPI_finish ();
+
+ PG_RETURN_VOID ();
+}
+
+
+/*
+Datum
+pg_spi_select_pair_from_y(PG_FUNCTION_ARGS)
+{
+ int ret;
+ valuest result;
+ bool isnull;
+ char *query = "SELECT 1,1 FROM Y";
+ result.col1 = 0;
+ result.col2 = 0;
+
+ if ((ret = SPI_connect()) < 0) {
+ fprintf(stderr, "SPI_connect returned %d\n", ret);
+ exit(1);
+ }
+ ret = SPI_exec(query, 0);
+ if (ret == SPI_OK_SELECT && SPI_processed > 0) {
+ int i;
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+ for (i = 0; i < SPI_processed; i++) {
+ HeapTuple tuple = tuptable->vals[i];
+ result.col1 = SPI_getbinval(tuple, tupdesc, 1, &isnull);
+ result.col2 = SPI_getbinval(tuple, tupdesc, 2, &isnull);
+ }
+ }
+ SPI_finish();
+ PG_RETURN_TEXT_P(result);
+}
+*/
+
+// SELECT X FROM Y WHERE Z=$1
+/*
+Datum
+pg_spi_select_with_cond(PG_FUNCTION_ARGS)
+{
+ int ret;
+ char *query;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ uint64 proc;
+ query = "SELECT col1 FROM Y WHERE col2 = $1";
+
+ ret = SPI_connect();
+ if (ret != SPI_OK_CONNECT) {
+ elog(ERROR, "SPI_connect failed: %d", ret);
+ }
+ nargs = 1;
+ argtypes[0] = INT4OID;
+ values[0] = Int32GetDatum(2);
+
+ ret = SPI_execute_with_args(query, nargs, argtypes, values, NULL, false, 0);
+ proc = SPI_processed;
+ if (ret != SPI_OK_SELECT)
+ {
+ elog(ERROR, "SPI_execute_with_args failed");
+ }
+
+ SPI_finish();
+
+
+ PG_RETURN_INT64(proc);
+ }*/
+
+////////SELECT WITH COND
+/*
+Datum pg_spi_prepare_select_with_cond(PG_FUNCTION_ARGS) {
+ static SPIPlanPtr prepared_plan = NULL;
+ SPIPlanPtr new_plan;
+ int ret;
+ Datum values[1];
+ uint64 proc;
+ int nargs;
+ Oid argtypes[1];
+ char *query = "SELECT col1 FROM Y WHERE col1 = $1";
+ int result = 0;
+
+ ret = SPI_connect();
+ if (ret != SPI_OK_CONNECT)
+ elog(ERROR, "SPI_connect failed ! \n");
+
+ if (prepared_plan == NULL) {
+
+ argtypes[0] = INT4OID;
+ nargs = 1;
+ values[0] = DatumGetByteaP(SPI_getbinval(tuptable->vals[0], tupdesc, 1, &isnull)); //Value col2
+
+ new_plan = SPI_prepare(query, nargs, argtypes);
+ if (new_plan == NULL)
+ elog(ERROR, "SPI_prepare failed ! \n");
+
+ prepared_plan = SPI_saveplan(new_plan);
+ if (prepared_plan == NULL)
+ elog(ERROR, "SPI_saveplan failed ! \n");
+ }
+
+
+ ret = SPI_execute_plan(prepared_plan, values, NULL, false, 0);
+
+ if (ret != SPI_OK_SELECT) {
+ elog(ERROR, "SPI_execute_plan failed: %d \n", ret);
+ }
+
+ proc = SPI_processed;
+
+ if (proc > 0) {
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+ HeapTuple tuple;
+ int i;
+
+ for (i = 0; i < proc; i++) {
+ tuple = tuptable->vals[i];
+ for (int j = 1; j <= tupdesc->natts; j++) {
+ char * value = SPI_getvalue(tuple, tupdesc, j);
+ result += atoi(value);
+ }
+ }
+ }
+ SPI_finish();
+ PG_RETURN_INT64(result);
+}
+*/
+
+Datum
+pg_spi_prepare_select_with_cond_without_saveplan (PG_FUNCTION_ARGS)
+{
+
+ SPIPlanPtr new_plan;
+ int ret;
+ Datum values[1];
+ uint64 proc;
+ int nargs;
+ Oid argtypes[1];
+ char *query = "SELECT col1 FROM Y WHERE col2 = $1";
+ int result = 0;
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ elog (ERROR, "SPI_connect failed ! \n");
+
+ {
+
+ argtypes[0] = INT4OID;
+ nargs = 1;
+ values[0] = Int32GetDatum (2); // Value col2
+
+ new_plan = SPI_prepare (query, nargs, argtypes);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare failed ! \n");
+
+ }
+
+
+ ret = SPI_execute_plan (new_plan, values, NULL, false, 0);
+
+ if (ret != SPI_OK_SELECT)
+ {
+ elog (ERROR, "SPI_execute_plan failed: %d \n", ret);
+ }
+
+ proc = SPI_processed;
+
+ if (proc > 0)
+ {
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+ HeapTuple tuple;
+ int i;
+
+ for (i = 0; i < proc; i++)
+ {
+ tuple = tuptable->vals[i];
+ for (int j = 1; j <= tupdesc->natts; j++)
+ {
+ char *value = SPI_getvalue (tuple, tupdesc, j);
+ result += atoi (value);
+ }
+ }
+ }
+ SPI_finish ();
+ PG_RETURN_INT64 (result);
+}
+
+
+Datum
+pg_spi_update_y (PG_FUNCTION_ARGS)
+{
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ const char *query = "UPDATE Y SET col1 = 4 WHERE (col2 = $1)";
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed ! \n");
+ }
+
+ nargs = 1;
+ argtypes[0] = INT4OID;
+ values[0] = Int32GetDatum (0);
+
+ ret = SPI_execute_with_args (query, nargs, argtypes, values, NULL, false, 0);
+ if (ret != SPI_OK_UPDATE)
+ {
+ elog (ERROR, "SPI_execute_with_args failed ! \n");
+ }
+
+ SPI_finish ();
+
+ PG_RETURN_VOID ();
+}
+
+
+Datum
+pg_spi_prepare_update (PG_FUNCTION_ARGS)
+{
+ static SPIPlanPtr prepared_plan = NULL;
+ SPIPlanPtr new_plan;
+ int ret;
+ int nargs;
+ Oid argtypes[1];
+ Datum values[1];
+ const char *query = "UPDATE Y SET col1 = 4 WHERE (col2 = $1)";
+
+ ret = SPI_connect ();
+ if (ret != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "SPI_connect failed ! \n");
+ }
+
+ if (prepared_plan == NULL)
+ {
+ argtypes[0] = INT4OID;
+ nargs = 1;
+ values[0] = Int32GetDatum (3);
+ // PREPARE
+ new_plan = SPI_prepare (query, nargs, argtypes);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare failed ! \n");
+ // SAVEPLAN
+ prepared_plan = SPI_saveplan (new_plan);
+ if (prepared_plan == NULL)
+ elog (ERROR, "SPI_saveplan failed ! \n");
+ }
+ ret = SPI_execute_plan (prepared_plan, values, NULL, false, 0);
+ if (ret != SPI_OK_UPDATE)
+ elog (ERROR, "SPI_execute_plan failed ! \n");
+
+ SPI_finish ();
+ PG_RETURN_VOID ();
+}
+
+
+/*
+Datum
+pg_spi_prepare_update_without_saveplan(PG_FUNCTION_ARGS)
+{}*/
+void
+_PG_fini (void)
+{
+}
+
+
+/*
+
+*/
+
+
+Datum
+pg_spi_get_dep_ref_fees (PG_FUNCTION_ARGS)
+{
+ /* Define plan to save */
+ static SPIPlanPtr deposit_plan;
+ static SPIPlanPtr ref_plan;
+ static SPIPlanPtr fees_plan;
+ static SPIPlanPtr dummy_plan;
+ /* Define variables to update */
+ Timestamp refund_deadline = PG_GETARG_TIMESTAMP (0);
+ bytea *merchant_pub = PG_GETARG_BYTEA_P (1);
+ bytea *wire_target_h_payto = PG_GETARG_BYTEA_P (2);
+ bytea *wtid_raw = PG_GETARG_BYTEA_P (3);
+ bool is_null;
+ /* Define variables to store the results of each SPI query */
+ uint64_t sum_deposit_val = 0;
+ uint32_t sum_deposit_frac = 0;
+ uint64_t s_refund_val = 0;
+ uint32_t s_refund_frac = 0;
+ uint64_t sum_dep_fee_val = 0;
+ uint32_t sum_dep_fee_frac = 0;
+ uint64_t norm_refund_val = 0;
+ uint32_t norm_refund_frac = 0;
+ uint64_t sum_refund_val = 0;
+ uint32_t sum_refund_frac = 0;
+ /* Define variables to store the Tuptable */
+ SPITupleTable *dep_res;
+ SPITupleTable *ref_res;
+ SPITupleTable *ref_by_coin_res;
+ SPITupleTable *norm_ref_by_coin_res;
+ SPITupleTable *fully_refunded_coins_res;
+ SPITupleTable *fees_res;
+ SPITupleTable *dummys_res;
+ /* Define variable to update */
+ Datum values_refund[2];
+ Datum values_deposit[3];
+ Datum values_fees[2];
+ Datum values_dummys[2];
+ TupleDesc tupdesc;
+ /* Define variables to replace some tables */
+ bytea *ref_by_coin_coin_pub;
+ int64 ref_by_coin_deposit_serial_id = 0;
+ bytea *norm_ref_by_coin_coin_pub;
+ int64_t norm_ref_by_coin_deposit_serial_id = 0;
+ bytea *new_dep_coin_pub = NULL;
+ int res = SPI_connect ();
+
+ /* Connect to SPI */
+ if (res < 0)
+ {
+ elog (ERROR, "Could not connect to SPI manager");
+ }
+ if (deposit_plan == NULL)
+ {
+ const char *dep_sql;
+ SPIPlanPtr new_plan;
+
+ // Execute first query and store results in variables
+ dep_sql =
+ "UPDATE deposits SET done=TRUE "
+ "WHERE NOT (done OR policy_blocked) "
+ "AND refund_deadline=$1 "
+ "AND merchant_pub=$2 "
+ "AND wire_target_h_payto=$3 "
+ "RETURNING "
+ "deposit_serial_id,"
+ "coin_pub,"
+ "amount_with_fee_val,"
+ "amount_with_fee_frac;";
+ fprintf (stderr, "dep sql %d\n", 1);
+ new_plan =
+ SPI_prepare (dep_sql, 4,(Oid[]){INT8OID, BYTEAOID, BYTEAOID});
+ fprintf (stderr, "dep sql %d\n", 2);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare failed for dep \n");
+ deposit_plan = SPI_saveplan (new_plan);
+ if (deposit_plan == NULL)
+ elog (ERROR, "SPI_saveplan failed for dep \n");
+ }
+ fprintf (stdout, "dep sql %d\n", 3);
+
+ values_deposit[0] = Int64GetDatum (refund_deadline);
+ values_deposit[1] = PointerGetDatum (merchant_pub);
+ values_deposit[2] = PointerGetDatum (wire_target_h_payto);
+
+ res = SPI_execute_plan (deposit_plan,
+ values_deposit,
+ NULL,
+ true,
+ 0);
+ fprintf (stdout, "dep sql %d\n", 4);
+ if (res != SPI_OK_UPDATE)
+ {
+ elog (ERROR, "Failed to execute subquery 1 \n");
+ }
+ // STORE TUPTABLE deposit
+ dep_res = SPI_tuptable;
+
+ for (unsigned int i = 0; i < SPI_processed; i++)
+ {
+ int64 dep_deposit_serial_ids = DatumGetInt64 (SPI_getbinval (
+ SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc, 1,
+ &is_null));
+ bytea *dep_coin_pub = DatumGetByteaP (SPI_getbinval (SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc,
+ 2, &is_null));
+ int64 dep_amount_val = DatumGetInt64 (SPI_getbinval (SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc,
+ 3, &is_null));
+ int32 dep_amount_frac = DatumGetInt32 (SPI_getbinval (SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc,
+ 4, &is_null));
+
+ if (is_null)
+ elog (ERROR, "Failed to retrieve data from deposit \n");
+ if (ref_plan == NULL)
+ {
+ // Execute second query with parameters from first query and store results in variables
+ const char *ref_sql =
+ "SELECT amount_with_fee_val, amount_with_fee_frac, coin_pub, deposit_serial_id "
+ "FROM refunds "
+ "WHERE coin_pub=$1 "
+ "AND deposit_serial_id=$2;";
+ SPIPlanPtr new_plan = SPI_prepare (ref_sql, 3, (Oid[]){BYTEAOID,
+ INT8OID});
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare failed for refund\n");
+ ref_plan = SPI_saveplan (new_plan);
+ if (ref_plan == NULL)
+ elog (ERROR, "SPI_saveplan failed for refund\n");
+ }
+ values_refund[0] = PointerGetDatum (dep_coin_pub);
+ values_refund[1] = Int64GetDatum (dep_deposit_serial_ids);
+ res = SPI_execute_plan (ref_plan,
+ values_refund,
+ NULL,
+ false,
+ 0);
+ if (res != SPI_OK_SELECT)
+ elog (ERROR, "Failed to execute subquery 2\n");
+ // STORE TUPTABLE refund
+ ref_res = SPI_tuptable;
+ for (unsigned int j = 0; j < SPI_processed; j++)
+ {
+ int64 ref_refund_val = DatumGetInt64 (SPI_getbinval (
+ SPI_tuptable->vals[j],
+ SPI_tuptable->tupdesc, 1,
+ &is_null));
+ int32 ref_refund_frac = DatumGetInt32 (SPI_getbinval (
+ SPI_tuptable->vals[j],
+ SPI_tuptable->tupdesc, 2,
+ &is_null));
+ bytea *ref_coin_pub = DatumGetByteaP (SPI_getbinval (
+ SPI_tuptable->vals[j],
+ SPI_tuptable->tupdesc, 3,
+ &is_null));
+ int64 ref_deposit_serial_id = DatumGetInt64 (SPI_getbinval (
+ SPI_tuptable->vals[j],
+ SPI_tuptable->tupdesc, 4,
+ &is_null));
+ // Execute third query with parameters from second query and store results in variables
+ ref_by_coin_coin_pub = ref_coin_pub;
+ ref_by_coin_deposit_serial_id = ref_deposit_serial_id;
+ // LOOP TO GET THE SUM FROM REFUND BY COIN
+ for (unsigned int i = 0; i<SPI_processed; i++)
+ {
+ if ((ref_by_coin_coin_pub ==
+ DatumGetByteaP (SPI_getbinval (SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc, 1,
+ &is_null)))
+ &&
+ (ref_by_coin_deposit_serial_id ==
+ DatumGetUInt64 (SPI_getbinval (SPI_tuptable->vals[i],
+ SPI_tuptable->tupdesc, 2,
+ &is_null)))
+ )
+ {
+ sum_refund_val += ref_refund_val;
+ sum_refund_frac += ref_refund_frac;
+ norm_ref_by_coin_coin_pub = ref_by_coin_coin_pub;
+ norm_ref_by_coin_deposit_serial_id = ref_by_coin_deposit_serial_id;
+ }
+ }// END SUM CALCULATION
+ // NORMALIZE REFUND VAL FRAC
+ norm_refund_val =
+ (sum_refund_val + sum_refund_frac) / 100000000;
+ norm_refund_frac =
+ sum_refund_frac % 100000000;
+ // Get refund values
+ s_refund_val += sum_refund_val;
+ s_refund_frac = sum_refund_frac;
+ }// END REFUND
+ if (norm_ref_by_coin_coin_pub == dep_coin_pub
+ && ref_by_coin_deposit_serial_id == dep_deposit_serial_ids
+ && norm_refund_val == dep_amount_val
+ && norm_refund_frac == dep_amount_frac)
+ {
+ new_dep_coin_pub = dep_coin_pub;
+ }
+ // Ensure we get the fee for each coin and not only once per denomination
+ if (fees_plan == NULL)
+ {
+ const char *fees_sql =
+ "SELECT "
+ " denom.fee_deposit_val AS fee_val, "
+ " denom.fee_deposit_frac AS fee_frac, "
+ "FROM known_coins kc"
+ "JOIN denominations denom USING (denominations_serial) "
+ "WHERE kc.coin_pub = $1 AND kc.coin_pub != $2;";
+ SPIPlanPtr new_plan = SPI_prepare (fees_sql, 3, (Oid[]){BYTEAOID,
+ BYTEAOID});
+ if (new_plan == NULL)
+ {
+ elog (ERROR, "SPI_prepare for fees failed ! \n");
+ }
+ fees_plan = SPI_saveplan (new_plan);
+ if (fees_plan == NULL)
+ {
+ elog (ERROR, "SPI_saveplan for fees failed ! \n");
+ }
+ }
+ values_fees[0] = PointerGetDatum (dep_coin_pub);
+ values_fees[1] = PointerGetDatum (new_dep_coin_pub);
+ res = SPI_execute_plan (fees_plan, values_fees, NULL, false, 0);
+ if (res != SPI_OK_SELECT)
+ elog (ERROR, "SPI_execute_plan failed for fees \n");
+ fees_res = SPI_tuptable;
+ tupdesc = fees_res->tupdesc;
+ for (unsigned int i = 0; i<SPI_processed; i++)
+ {
+ HeapTuple tuple = fees_res->vals[i];
+ bool is_null;
+ uint64_t fee_val = DatumGetUInt64 (SPI_getbinval (tuple, tupdesc, 1,
+ &is_null));
+ uint32_t fee_frac = DatumGetUInt32 (SPI_getbinval (tuple, tupdesc, 2,
+ &is_null));
+ uint64_t fees_deposit_serial_id = DatumGetUInt64 (SPI_getbinval (tuple,
+ tupdesc,
+ 3,
+ &is_null));
+ if (dummy_plan == NULL)
+ {
+ const char *insert_dummy_sql =
+ "INSERT INTO "
+ "aggregation_tracking(deposit_serial_id, wtid_raw)"
+ " VALUES ($1, $2)";
+
+ SPIPlanPtr new_plan = SPI_prepare (insert_dummy_sql, 2, (Oid[]){INT8OID,
+ BYTEAOID});
+ if (new_plan == NULL)
+ elog (ERROR, "FAILED to prepare aggregation tracking \n");
+ dummy_plan = SPI_saveplan (new_plan);
+ if (dummy_plan == NULL)
+ elog (ERROR, "FAILED to saveplan aggregation tracking\n");
+ }
+ values_dummys[0] = Int64GetDatum (dep_deposit_serial_ids);
+ values_dummys[1] = PointerGetDatum (wtid_raw);
+ res = SPI_execute_plan (dummy_plan, values_dummys, NULL, false, 0);
+ if (res != SPI_OK_INSERT)
+ elog (ERROR, "Failed to insert dummy\n");
+ dummys_res = SPI_tuptable;
+ // Calculation of deposit fees for not fully refunded deposits
+ sum_dep_fee_val += fee_val;
+ sum_dep_fee_frac += fee_frac;
+ }
+ // Get deposit values
+ sum_deposit_val += dep_amount_val;
+ sum_deposit_frac += dep_amount_frac;
+ }// END DEPOSIT
+ SPI_finish ();
+ PG_RETURN_VOID ();
+}
diff --git a/src/exchangedb/spi/own_test.control b/src/exchangedb/spi/own_test.control
new file mode 100644
index 000000000..4e73e207f
--- /dev/null
+++ b/src/exchangedb/spi/own_test.control
@@ -0,0 +1,4 @@
+comment = 'Example extension for testing purposes'
+default_version = '1.0'
+module_pathname = '$libdir/own_test'
+relocatable = true
diff --git a/src/exchangedb/spi/own_test.sql b/src/exchangedb/spi/own_test.sql
new file mode 100644
index 000000000..12729d068
--- /dev/null
+++ b/src/exchangedb/spi/own_test.sql
@@ -0,0 +1,201 @@
+DROP TABLE IF EXISTS X;
+CREATE TABLE X (
+ a integer
+);
+
+INSERT INTO X (a)
+ VALUES (1), (2), (3), (4), (5), (6), (7);
+
+DROP TABLE IF EXISTS Y;
+CREATE TABLE Y (col1 INT, col2 INT);
+INSERT INTO Y (col1,col2)
+ VALUES (1,2), (2,0), (0,4), (4,0), (0,6), (6,7), (7,8);
+
+DROP TABLE IF EXISTS Z;
+CREATE TABLE Z (col1 BYTEA);
+
+DROP TABLE IF EXISTS deposits;
+CREATE TABLE deposits(
+ deposit_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,shard INT8 NOT NULL
+ ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)
+ ,known_coin_id INT8 NOT NULL
+ ,amount_with_fee_val INT8 NOT NULL
+ ,amount_with_fee_frac INT4 NOT NULL
+ ,wallet_timestamp INT8 NOT NULL
+ ,exchange_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_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)
+ ,coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)
+ ,wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16)
+ ,wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)
+ ,done BOOLEAN NOT NULL DEFAULT FALSE
+ ,policy_blocked BOOLEAN NOT NULL DEFAULT FALSE
+ ,policy_details_serial_id INT8);
+
+
+DROP FUNCTION IF EXISTS pg_spi_insert_int;
+CREATE FUNCTION pg_spi_insert_int()
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_insert_int';
+
+DROP FUNCTION IF EXISTS pg_spi_select_from_x;
+CREATE FUNCTION pg_spi_select_from_x()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_select_from_x';
+
+/*
+CREATE FUNCTION pg_spi_select_pair_from_y()
+ RETURNS valuest
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_select_pair_from_y';
+*/
+/*CREATE FUNCTION pg_spi_select_with_cond()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_select_with_cond';
+*/
+
+DROP FUNCTION IF EXISTS pg_spi_update_y;
+CREATE FUNCTION pg_spi_update_y()
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_update_y';
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_example;
+CREATE FUNCTION pg_spi_prepare_example()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_example';
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_example_without_saveplan;
+CREATE FUNCTION pg_spi_prepare_example_without_saveplan()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_example_without_saveplan';
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_insert;
+CREATE FUNCTION pg_spi_prepare_insert()
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_insert';
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_insert_without_saveplan;
+CREATE FUNCTION pg_spi_prepare_insert_without_saveplan()
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_insert_without_saveplan';
+
+/*
+CREATE FUNCTION pg_spi_prepare_select_with_cond()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_select_with_cond';
+*/
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_select_with_cond_without_saveplan;
+CREATE FUNCTION pg_spi_prepare_select_with_cond_without_saveplan()
+ RETURNS INT8
+ LANGUAGE c COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_select_with_cond_without_saveplan';
+
+DROP FUNCTION IF EXISTS pg_spi_prepare_update;
+CREATE FUNCTION pg_spi_prepare_update()
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_prepare_update';
+
+DROP FUNCTION IF EXISTS pg_spi_get_dep_ref_fees;
+CREATE FUNCTION pg_spi_get_dep_ref_fees(
+ IN in_timestamp INT8
+ ,IN merchant_pub BYTEA
+ ,IN wire_target_h_payto BYTEA
+ ,IN wtid BYTEA
+)
+ RETURNS VOID
+ LANGUAGE c VOLATILE COST 100
+AS '$libdir/own_test', 'pg_spi_get_dep_ref_fees';
+
+DROP FUNCTION IF EXISTS update_pg_spi_get_dep_ref_fees;
+CREATE FUNCTION update_pg_spi_get_dep_ref_fees(
+ IN in_refund_deadline INT8,
+ IN in_merchant_pub BYTEA,
+ IN in_wire_target_h_payto BYTEA
+)
+RETURNS SETOF record
+LANGUAGE plpgsql VOLATILE
+AS $$
+DECLARE
+
+BEGIN
+RETURN QUERY
+ UPDATE deposits
+ SET done = TRUE
+ WHERE NOT (done OR policy_blocked)
+ AND refund_deadline < in_refund_deadline
+ AND merchant_pub = in_merchant_pub
+ AND wire_target_h_payto = in_wire_target_h_payto
+ RETURNING
+ deposit_serial_id,
+ coin_pub,
+ amount_with_fee_val,
+ amount_with_fee_frac;
+END $$;
+
+DROP FUNCTION IF EXISTS stored_procedure_update;
+CREATE FUNCTION stored_procedure_update(
+IN in_number INT8
+)
+RETURNS VOID
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ UPDATE Y
+ SET col1 = 4
+ WHERE col2 = in_number;
+END $$;
+
+DROP FUNCTION IF EXISTS stored_procedure_select;
+CREATE FUNCTION stored_procedure_select(OUT out_value INT8)
+RETURNS INT8
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ SELECT 1
+ INTO out_value
+ FROM X;
+ RETURN;
+END $$;
+
+
+DROP FUNCTION IF EXISTS stored_procedure_insert;
+CREATE FUNCTION stored_procedure_insert(
+IN in_number INT8,
+OUT out_number INT8)
+RETURNS INT8
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ INSERT INTO X (a)
+ VALUES (in_number)
+ RETURNING a INTO out_number;
+END $$;
+
+DROP FUNCTION IF EXISTS stored_procedure_select_with_cond;
+CREATE FUNCTION stored_procedure_select_with_cond(
+IN in_number INT8,
+OUT out_number INT8
+)
+RETURNS INT8
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ SELECT col1 INTO out_number
+ FROM Y
+ WHERE col2 = in_number;
+ RETURN;
+END $$;
diff --git a/src/exchangedb/spi/perf_own_test.c b/src/exchangedb/spi/perf_own_test.c
new file mode 100644
index 000000000..92be2235e
--- /dev/null
+++ b/src/exchangedb/spi/perf_own_test.c
@@ -0,0 +1,25 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file exchangedb/spi/perf_own_test.c
+ * @brief benchmark for 'own_test'
+ * @author Joseph Xu
+ */
+#include "exchangedb/platform.h"
+#include "exchangedb/taler_exchangedb_lib.h"
+#include "exchangedb/taler_json_lib.h"
+#include "exchangedb/taler_exchangedb_plugin.h"
+#include "own_test.sql"
diff --git a/src/exchangedb/spi/pg_aggregate.c b/src/exchangedb/spi/pg_aggregate.c
new file mode 100644
index 000000000..721f247c7
--- /dev/null
+++ b/src/exchangedb/spi/pg_aggregate.c
@@ -0,0 +1,411 @@
+#include "postgres.h"
+#include "fmgr.h"
+#include "utils/numeric.h"
+#include "utils/builtins.h"
+#include "executor/spi.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1 (get_deposit_summary);
+
+Datum
+get_deposit_summary (PG_FUNCTION_ARGS)
+{
+
+ static SPIPlanPtr deposit_plan;
+ static SPIPlanPtr refund_plan;
+ static SPIPlanPtr refund_by_coin_plan;
+ static SPIPlanPtr norm_refund_by_coin_plan;
+ static SPIPlanPtr fully_refunded_by_coins_plan;
+ static SPIPlanPtr fees_plan;
+
+ int shard = PG_GETARG_INT32 (0);
+ char *sql;
+ char *merchant_pub = text_to_cstring (PG_GETARG_TEXT_P (1));
+ char *wire_target_h_payto = text_to_cstring (PG_GETARG_TEXT_P (2));
+ char *wtid_raw = text_to_cstring (PG_GETARG_TEXT_P (3));
+ int refund_deadline = PG_GETARG_INT32 (4);
+ int conn = SPI_connect ();
+ if (conn != SPI_OK_CONNECT)
+ {
+ elog (ERROR, "DB connection failed ! \n");
+ }
+
+ if (deposit_plan == NULL
+ || refund_plan == NULL
+ || refund_by_coin_plan == NULL
+ || norm_refund_by_coin_plan = NULL
+ || fully_refunded_coins_plan = NULL
+ || fees_plan
+ == NULL)
+ {
+ if (deposit_plan == NULL)
+ {
+ int nargs = 3;
+ Oid argtypes[3];
+ argtypes[0] = INT8OID;
+ argtypes[1] = BYTEAOID;
+ argtypes[2] = BYTEAOID;
+ const char *dep_sql =
+ " UPDATE deposits"
+ " SET done=TRUE"
+ " WHERE NOT (done OR policy_blocked)"
+ " AND refund_deadline < $1"
+ " AND merchant_pub = $2"
+ " AND wire_target_h_payto = $3"
+ " RETURNING"
+ " deposit_serial_id"
+ " ,coin_pub"
+ " ,amount_with_fee_val AS amount_val"
+ " ,amount_with_fee_frac AS amount_frac";
+ SPIPlanPtr new_plan =
+ SPI_prepare (dep_sql, 4, argtypes);
+ if (new_plan == NULL)
+ {
+ elog (ERROR, "SPI_prepare for deposit failed ! \n");
+ }
+ deposit_plan = SPI_saveplan (new_plan);
+ if (deposit_plan == NULL)
+ {
+ elog (ERROR, "SPI_saveplan for deposit failed ! \n");
+ }
+ }
+
+ Datum values[4];
+ values[0] = Int64GetDatum (refund_deadline);
+ values[1] = CStringGetDatum (merchant_pub);
+ values[2] = CStringGetDatum (wire_target_h_payto);
+ int ret = SPI_execute_plan (deposit_plan,
+ values,
+ NULL,
+ true,
+ 0);
+ if (ret != SPI_OK_UPDATE)
+ {
+ elog (ERROR, "Failed to execute subquery 1\n");
+ }
+ uint64_t *dep_deposit_serial_ids = palloc (sizeof(uint64_t)
+ * SPI_processed);
+ BYTEA **dep_coin_pubs = palloc (sizeof(BYTEA *) * SPI_processed);
+ uint64_t *dep_amount_vals = palloc (sizeof(uint64_t) * SPI_processed);
+ uint32_t *dep_amount_fracs = palloc (sizeof(uint32_t) * SPI_processed);
+ for (unsigned int i = 0; i < SPI_processed; i++)
+ {
+ HeapTuple tuple = SPI_tuptable->vals[i];
+ dep_deposit_serial_ids[i] =
+ DatumGetInt64 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 1, &ret));
+ dep_coin_pubs[i] =
+ DatumGetByteaP (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 2, &ret));
+ dep_amount_vals[i] =
+ DatumGetInt64 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 3, &ret));
+ dep_amount_fracs[i] =
+ DatumGetInt32 (SPI_getbinval (tuple, SPI_tuptable->tupdesc, 4, &ret));
+ }
+
+
+ if (refund_plan == NULL)
+ {
+ const char *ref_sql =
+ "ref AS ("
+ " SELECT"
+ " amount_with_fee_val AS refund_val"
+ " ,amount_with_fee_frac AS refund_frac"
+ " ,coin_pub"
+ " ,deposit_serial_id"
+ " FROM refunds"
+ " WHERE coin_pub IN (SELECT coin_pub FROM dep)"
+ " AND deposit_serial_id IN (SELECT deposit_serial_id FROM dep)) ";
+ SPIPlanPtr new_plan = SPI_prepare (ref_sql, 0, NULL);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare for refund failed ! \n");
+ refund_plan = SPI_saveplan (new_plan);
+ if (refund_plan == NULL)
+ {
+ elog (ERROR, "SPI_saveplan for refund failed ! \n");
+ }
+ }
+
+ int64t_t *ref_deposit_serial_ids = palloc (sizeof(int64_t) * SPI_processed);
+
+ int res = SPI_execute_plan (refund_plan, NULL, NULL, false, 0);
+ if (res != SPI_OK_SELECT)
+ {
+ elog (ERROR, "Failed to execute subquery 2\n");
+ }
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+ for (unsigned int i = 0; i < SPI_processed; i++)
+ {
+ HeapTuple tuple = tuptable->vals[i];
+ Datum refund_val = SPI_getbinval (tuple, tupdesc, 1, &refund_val_isnull);
+ Datum refund_frac = SPI_getbinval (tuple, tupdesc, 2,
+ &refund_frac_isnull);
+ Datum coin_pub = SPI_getbinval (tuple, tupdesc, 3, &coin_pub_isnull);
+ Datum deposit_serial_id = SPI_getbinval (tuple, tupdesc, 4,
+ &deposit_serial_id_isnull);
+ if (refund_val_isnull
+ || refund_frac_isnull
+ || coin_pub_isnull
+ || deposit_serial_id_isnull)
+ {
+ elog (ERROR, "Failed to retrieve data from subquery 2");
+ }
+ uint64_t refund_val_int = DatumGetUInt64 (refund_val);
+ uint32_t refund_frac_int = DatumGetUInt32 (refund_frac);
+ BYTEA coin_pub = DatumGetByteaP (coin_pub);
+ ref_deposit_serial_ids = DatumGetInt64 (deposit_serial_id);
+
+ refund *new_refund = (refund*) palloc (sizeof(refund));
+ new_refund->coin_pub = coin_pub_str;
+ new_refund->deposit_serial_id = deposit_serial_id_int;
+ new_refund->amount_with_fee_val = refund_val_int;
+ new_refund->amount_with_fee_frac = refund_frac_int;
+ }
+
+
+ if (refund_by_coin_plan == NULL)
+ {
+ const char *ref_by_coin_sql =
+ "ref_by_coin AS ("
+ " SELECT"
+ " SUM(refund_val) AS sum_refund_val"
+ " ,SUM(refund_frac) AS sum_refund_frac"
+ " ,coin_pub"
+ " ,deposit_serial_id"
+ " FROM ref"
+ " GROUP BY coin_pub, deposit_serial_id) ";
+ SPIPlanPtr new_plan = SPI_prepare (ref_by_coin_sql, 0, NULL);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare for refund by coin failed ! \n");
+ refund_by_coin_plan = SPI_saveplan (new_plan);
+ if (refund_by_coin_plan == NULL)
+ elog (ERROR, "SPI_saveplan for refund failed");
+ }
+
+
+ int res = SPI_execute_plan (refund_by_coin_plan, NULL, NULL, false, 0);
+ if (res != SPI_OK_SELECT)
+ {
+ elog (ERROR, "Failed to execute subquery 2\n");
+ }
+
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+ for (unsigned int i = 0; i < SPI_processed; i++)
+ {
+ HeapTuple tuple = tuptable->vals[i];
+ Datum sum_refund_val = SPI_getbinval (tuple, tupdesc, 1,
+ &refund_val_isnull);
+ Datum sum_refund_frac = SPI_getbinval (tuple, tupdesc, 2,
+ &refund_frac_isnull);
+ Datum coin_pub = SPI_getbinval (tuple, tupdesc, 3, &coin_pub_isnull);
+ Datum deposit_serial_id_int = SPI_getbinval (tuple, tupdesc, 4,
+ &deposit_serial_id_isnull);
+ if (refund_val_isnull
+ || refund_frac_isnull
+ || coin_pub_isnull
+ || deposit_serial_id_isnull)
+ {
+ elog (ERROR, "Failed to retrieve data from subquery 2");
+ }
+ uint64_t s_refund_val_int = DatumGetUInt64 (sum_refund_val);
+ uint32_t s_refund_frac_int = DatumGetUInt32 (sum_refund_frac);
+ BYTEA coin_pub = DatumGetByteaP (coin_pub);
+ uint64_t deposit_serial_id_int = DatumGetInt64 (deposit_serial_id_int);
+ refund *new_refund_by_coin = (refund*) palloc (sizeof(refund));
+ new_refund_by_coin->coin_pub = coin_pub;
+ new_refund_by_coin->deposit_serial_id = deposit_serial_id_int;
+ new_refund_by_coin->refund_amount_with_fee_val = s_refund_val_int;
+ new_refund_by_coin->refund_amount_with_fee_frac = s_refund_frac_int;
+ }
+
+
+ if (norm_refund_by_coin_plan == NULL)
+ {
+ const char *norm_ref_by_coin_sql =
+ "norm_ref_by_coin AS ("
+ " SELECT"
+ " coin_pub"
+ " ,deposit_serial_id"
+ " FROM ref_by_coin) ";
+ SPIPlanPtr new_plan = SPI_prepare (norm_ref_by_coin_sql, 0, NULL);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare for norm refund by coin failed ! \n");
+ norm_refund_by_coin_plan = SPI_saveplan (new_plan);
+ if (norm_refund_by_coin_plan == NULL)
+ elog (ERROR, "SPI_saveplan for norm refund by coin failed ! \n");
+ }
+
+ double norm_refund_val =
+ ((double) new_refund_by_coin->refund_amount_with_fee_val
+ + (double) new_refund_by_coin->refund_amount_with_fee_frac) / 100000000;
+ double norm_refund_frac =
+ (double) new_refund_by_coin->refund_amount_with_fee_frac % 100000000;
+
+ if (fully_refunded_coins_plan == NULL)
+ {
+ const char *fully_refunded_coins_sql =
+ "fully_refunded_coins AS ("
+ " SELECT"
+ " dep.coin_pub"
+ " FROM norm_ref_by_coin norm"
+ " JOIN dep"
+ " ON (norm.coin_pub = dep.coin_pub"
+ " AND norm.deposit_serial_id = dep.deposit_serial_id"
+ " AND norm.norm_refund_val = dep.amount_val"
+ " AND norm.norm_refund_frac = dep.amount_frac)) ";
+ SPIPlanPtr new_plan =
+ SPI_prepare (fully_refunded_coins_sql, 0, NULL);
+ if (new_plan == NULL)
+ elog (ERROR, "SPI_prepare for fully refunded coins failed ! \n");
+ fully_refunded_coins_plan = SPI_saveplan (new_plan);
+ if (fully_refunded_coins_plan == NULL)
+ elog (ERROR, "SPI_saveplan for fully refunded coins failed ! \n");
+ }
+
+ int res = SPI_execute_plan (fully_refunded_coins_sql);
+ if (res != SPI_OK_SELECT)
+ elog (ERROR, "Failed to execute subquery 4\n");
+ SPITupleTable *tuptable = SPI_tuptable;
+ TupleDesc tupdesc = tuptable->tupdesc;
+
+ BYTEA coin_pub = SPI_getbinval (tuple, tupdesc, 1, &coin_pub_isnull);
+ if (fees_plan == NULL)
+ {
+ const char *fees_sql =
+ "SELECT "
+ " denom.fee_deposit_val AS fee_val, "
+ " denom.fee_deposit_frac AS fee_frac, "
+ " cs.deposit_serial_id "
+ "FROM dep cs "
+ "JOIN known_coins kc USING (coin_pub) "
+ "JOIN denominations denom USING (denominations_serial) "
+ "WHERE coin_pub NOT IN (SELECT coin_pub FROM fully_refunded_coins)";
+ SPIPlanPtr new_plan =
+ SPI_prepare (fees_sql, 0, NULL);
+ if (new_plan == NULL)
+ {
+ elog (ERROR, "SPI_prepare for fees failed ! \n");
+ }
+ fees_plan = SPI_saveplan (new_plan);
+ if (fees_plan == NULL)
+ {
+ elog (ERROR, "SPI_saveplan for fees failed ! \n");
+ }
+ }
+ }
+ int fees_ntuples;
+ SPI_execute (fees_sql, true, 0);
+ if (SPI_result_code () != SPI_OK_SELECT)
+ {
+ ereport (
+ ERROR,
+ (errcode (ERRCODE_INTERNAL_ERROR),
+ errmsg ("deposit fee query failed: error code %d \n",
+ SPI_result_code ())));
+ }
+ fees_ntuples = SPI_processed;
+
+ if (fees_ntuples > 0)
+ {
+ for (i = 0; i < fees_ntuples; i++)
+ {
+ Datum fee_val_datum =
+ SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1,
+ &fee_null);
+ Datum fee_frac_datum =
+ SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2,
+ &fee_null);
+ Datum deposit_id_datum =
+ SPI_getbinval (SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 3,
+ &deposit_null);
+ if (! fee_null && ! deposit_null)
+ {
+ int64 fee_val = DatumGetInt64 (fee_val_datum);
+ int32 fee_frac = DatumGetInt32 (fee_frac_datum);
+ int64 deposit_id = DatumGetInt64 (deposit_id_datum);
+ sum_fee_value += fee_val;
+ sum_fee_fraction += fee_frac;
+ char *insert_agg_sql =
+ psprintf (
+ "INSERT INTO "
+ "aggregation_tracking(deposit_serial_id, wtid_raw)"
+ " VALUES (%lld, '%s')",
+ deposit_id, wtid_raw);
+ SPI_execute (insert_agg_sql, false, 0);
+ }
+ }
+ }
+
+ TupleDesc tupdesc;
+ SPITupleTable *tuptable = SPI_tuptable;
+ HeapTuple tuple;
+ Datum result;
+
+ if (tuptable == NULL || SPI_processed != 1)
+ {
+ ereport (
+ ERROR,
+ (errcode (ERRCODE_INTERNAL_ERROR),
+ errmsg ("Unexpected result \n")));
+ }
+ tupdesc = SPI_tuptable->tupdesc;
+ tuple = SPI_tuptable->vals[0];
+ result = HeapTupleGetDatum (tuple);
+
+ TupleDesc result_desc = CreateTemplateTupleDesc (6, false);
+ TupleDescInitEntry (result_desc, (AttrNumber) 1, "sum_deposit_value", INT8OID,
+ -1, 0);
+ TupleDescInitEntry (result_desc, (AttrNumber) 2, "sum_deposit_fraction",
+ INT4OID, -1, 0);
+ TupleDescInitEntry (result_desc, (AttrNumber) 3, "sum_refund_value", INT8OID,
+ -1, 0);
+ TupleDescInitEntry (result_desc, (AttrNumber) 4, "sum_refund_fraction",
+ INT4OID, -1, 0);
+ TupleDescInitEntry (result_desc, (AttrNumber) 5, "sum_fee_value", INT8OID, -1,
+ 0);
+ TupleDescInitEntry (result_desc, (AttrNumber) 6, "sum_fee_fraction", INT4OID,
+ -1, 0);
+
+ int ret = SPI_prepare (sql, 4, argtypes);
+ if (ret != SPI_OK_PREPARE)
+ {
+ elog (ERROR, "Failed to prepare statement: %s \n", sql);
+ }
+
+ ret = SPI_execute_plan (plan, args, nulls, true, 0);
+ if (ret != SPI_OK_SELECT)
+ {
+ elog (ERROR, "Failed to execute statement: %s \n", sql);
+ }
+
+ if (SPI_processed > 0)
+ {
+ HeapTuple tuple;
+ Datum values[6];
+ bool nulls[6] = {false};
+ values[0] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1,
+ &nulls[0]);
+ values[1] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2,
+ &nulls[1]);
+ values[2] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3,
+ &nulls[2]);
+ values[3] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4,
+ &nulls[3]);
+ values[4] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5,
+ &nulls[4]);
+ values[5] =
+ SPI_getbinval (SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 6,
+ &nulls[5]);
+ tuple = heap_form_tuple (result_desc, values, nulls);
+ PG_RETURN_DATUM (HeapTupleGetDatum (tuple));
+ }
+ SPI_finish ();
+
+ PG_RETURN_NULL ();
+}
diff --git a/src/exchangedb/test-exchangedb-batch-reserves-in-insert-postgres b/src/exchangedb/test-exchangedb-batch-reserves-in-insert-postgres
new file mode 100755
index 000000000..bc044232a
--- /dev/null
+++ b/src/exchangedb/test-exchangedb-batch-reserves-in-insert-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# test-exchangedb-batch-reserves-in-insert-postgres - temporary wrapper script for .libs/test-exchangedb-batch-reserves-in-insert-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The test-exchangedb-batch-reserves-in-insert-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "test-exchangedb-batch-reserves-in-insert-postgres:test-exchangedb-batch-reserves-in-insert-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "test-exchangedb-batch-reserves-in-insert-postgres:test-exchangedb-batch-reserves-in-insert-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "test-exchangedb-batch-reserves-in-insert-postgres:test-exchangedb-batch-reserves-in-insert-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='test-exchangedb-batch-reserves-in-insert-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/test-exchangedb-by-j-postgres b/src/exchangedb/test-exchangedb-by-j-postgres
new file mode 100755
index 000000000..11d295cc2
--- /dev/null
+++ b/src/exchangedb/test-exchangedb-by-j-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# test-exchangedb-by-j-postgres - temporary wrapper script for .libs/test-exchangedb-by-j-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The test-exchangedb-by-j-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "test-exchangedb-by-j-postgres:test-exchangedb-by-j-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "test-exchangedb-by-j-postgres:test-exchangedb-by-j-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "test-exchangedb-by-j-postgres:test-exchangedb-by-j-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='test-exchangedb-by-j-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/test-exchangedb-populate-link-data-postgres b/src/exchangedb/test-exchangedb-populate-link-data-postgres
new file mode 100755
index 000000000..f3d673519
--- /dev/null
+++ b/src/exchangedb/test-exchangedb-populate-link-data-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# test-exchangedb-populate-link-data-postgres - temporary wrapper script for .libs/test-exchangedb-populate-link-data-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The test-exchangedb-populate-link-data-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "test-exchangedb-populate-link-data-postgres:test-exchangedb-populate-link-data-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "test-exchangedb-populate-link-data-postgres:test-exchangedb-populate-link-data-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "test-exchangedb-populate-link-data-postgres:test-exchangedb-populate-link-data-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='test-exchangedb-populate-link-data-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/test-exchangedb-populate-ready-deposit-postgres b/src/exchangedb/test-exchangedb-populate-ready-deposit-postgres
new file mode 100755
index 000000000..7747f381c
--- /dev/null
+++ b/src/exchangedb/test-exchangedb-populate-ready-deposit-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# test-exchangedb-populate-ready-deposit-postgres - temporary wrapper script for .libs/test-exchangedb-populate-ready-deposit-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The test-exchangedb-populate-ready-deposit-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "test-exchangedb-populate-ready-deposit-postgres:test-exchangedb-populate-ready-deposit-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "test-exchangedb-populate-ready-deposit-postgres:test-exchangedb-populate-ready-deposit-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "test-exchangedb-populate-ready-deposit-postgres:test-exchangedb-populate-ready-deposit-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='test-exchangedb-populate-ready-deposit-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/test-exchangedb-populate-select-refunds-by-coin-postgres b/src/exchangedb/test-exchangedb-populate-select-refunds-by-coin-postgres
new file mode 100755
index 000000000..ce7ebb712
--- /dev/null
+++ b/src/exchangedb/test-exchangedb-populate-select-refunds-by-coin-postgres
@@ -0,0 +1,210 @@
+#! /bin/bash
+
+# test-exchangedb-populate-select-refunds-by-coin-postgres - temporary wrapper script for .libs/test-exchangedb-populate-select-refunds-by-coin-postgres
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-15
+#
+# The test-exchangedb-populate-select-refunds-by-coin-postgres program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' libtalerexchangedb.la ../../src/json/libtalerjson.la ../../src/util/libtalerutil.la ../../src/pq/libtalerpq.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "test-exchangedb-populate-select-refunds-by-coin-postgres:test-exchangedb-populate-select-refunds-by-coin-postgres:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-15" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "test-exchangedb-populate-select-refunds-by-coin-postgres:test-exchangedb-populate-select-refunds-by-coin-postgres:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "test-exchangedb-populate-select-refunds-by-coin-postgres:test-exchangedb-populate-select-refunds-by-coin-postgres:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='test-exchangedb-populate-select-refunds-by-coin-postgres'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/home/priscilla/exchange/src/exchangedb/.libs:/home/priscilla/exchange/src/json/.libs:/home/priscilla/exchange/src/util/.libs:/home/priscilla/exchange/src/pq/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 6d07d2149..22788a562 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -33,9 +33,9 @@ static int result;
/**
* Report line of error if @a cond is true, and jump to label "drop".
*/
-#define FAILIF(cond) \
+#define FAILIF(cond) \
do { \
- if (! (cond)) { break;} \
+ if (! (cond)) { break;} \
GNUNET_break (0); \
goto drop; \
} while (0)
@@ -45,7 +45,8 @@ static int result;
* Initializes @a ptr with random data.
*/
#define RND_BLK(ptr) \
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, \
+ sizeof (*ptr))
/**
* Initializes @a ptr with zeros.
@@ -278,7 +279,7 @@ create_denom_key_pair (unsigned int size,
GNUNET_assert (GNUNET_OK ==
TALER_denom_priv_create (&dkp->priv,
&dkp->pub,
- TALER_DENOMINATION_RSA,
+ GNUNET_CRYPTO_BSA_RSA,
size));
/* Using memset() as fields like master key and signature
are not properly initialized for this test. */
@@ -603,7 +604,7 @@ static struct TALER_PaytoHashP wire_target_h_payto;
/**
- * Callback for #select_deposits_above_serial_id ()
+ * Callback for #select_coin_deposits_above_serial_id ()
*
* @param cls closure
* @param rowid unique serial ID for the deposit in our DB
@@ -930,14 +931,17 @@ audit_wire_cb (void *cls,
/**
* Test API relating to wire_out handling.
*
+ * @param bd batch deposit to test
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
-test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
+test_wire_out (const struct TALER_EXCHANGEDB_BatchDeposit *bd)
{
+ const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = &bd->cdis[0];
struct TALER_PaytoHashP h_payto;
- TALER_payto_hash (deposit->receiver_wire_account,
+ GNUNET_assert (0 < bd->num_cdis);
+ TALER_payto_hash (bd->receiver_wire_account,
&h_payto);
auditor_row_cnt = 0;
memset (&wire_out_wtid,
@@ -955,8 +959,8 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
plugin->start_deferred_wire_out (plugin->cls));
/* setup values for wire transfer aggregation data */
- merchant_pub_wt = deposit->merchant_pub;
- h_contract_terms_wt = deposit->h_contract_terms;
+ merchant_pub_wt = bd->merchant_pub;
+ h_contract_terms_wt = bd->h_contract_terms;
coin_pub_wt = deposit->coin.coin_pub;
coin_value_wt = deposit->amount_with_fee;
@@ -980,6 +984,7 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
struct TALER_Amount coin_fee2;
struct GNUNET_TIME_Timestamp execution_time2;
struct TALER_EXCHANGEDB_KycStatus kyc;
+ enum TALER_AmlDecisionState aml;
h_contract_terms_wt2.hash.bits[0]++;
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
@@ -993,7 +998,8 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&execution_time2,
&coin_contribution2,
&coin_fee2,
- &kyc));
+ &kyc,
+ &aml));
}
{
struct TALER_ReservePublicKeyP rpub;
@@ -1025,6 +1031,7 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
struct TALER_Amount coin_fee2;
struct GNUNET_TIME_Timestamp execution_time2;
struct TALER_EXCHANGEDB_KycStatus kyc;
+ enum TALER_AmlDecisionState aml = TALER_AML_FROZEN;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->lookup_transfer_by_deposit (plugin->cls,
@@ -1037,7 +1044,9 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&execution_time2,
&coin_contribution2,
&coin_fee2,
- &kyc));
+ &kyc,
+ &aml));
+ FAILIF (TALER_AML_NORMAL != aml);
GNUNET_assert (0 == GNUNET_memcmp (&wtid2,
&wire_out_wtid));
GNUNET_assert (GNUNET_TIME_timestamp_cmp (execution_time2,
@@ -1084,9 +1093,9 @@ recoup_cb (void *cls,
const struct TALER_CoinPublicInfo *coin,
const struct TALER_DenominationPublicKey *denom_pub,
const struct TALER_CoinSpendSignatureP *coin_sig,
- const union TALER_DenominationBlindingKeyP *coin_blind)
+ const union GNUNET_CRYPTO_BlindingSecretP *coin_blind)
{
- const union TALER_DenominationBlindingKeyP *cb = cls;
+ const union GNUNET_CRYPTO_BlindingSecretP *cb = cls;
(void) rowid;
(void) timestamp;
@@ -1105,48 +1114,32 @@ drop:
/**
- * Function called on deposits that are past their due date
- * and have not yet seen a wire transfer.
+ * Function called on batch deposits that may require a
+ * wire transfer.
*
* @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
- * @param rowid deposit table row of the coin's deposit
- * @param coin_pub public key of the coin
- * @param amount value of the deposit, including fee
- * @param payto_uri where should the funds be wired
- * @param deadline what was the requested wire transfer deadline
- * @param done did the exchange claim that it made a transfer?
+ * @param batch_deposit_serial_id where in the table are we
+ * @param total_amount value of all missing deposits, including fees
+ * @param wire_target_h_payto hash of the recipient account's payto URI
+ * @param deadline what was the earliest requested wire transfer deadline
*/
static void
-wire_missing_cb (void *cls,
- uint64_t rowid,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *amount,
- const char *payto_uri,
- struct GNUNET_TIME_Timestamp deadline,
- bool done)
+wire_missing_cb (
+ void *cls,
+ uint64_t batch_deposit_serial_id,
+ const struct TALER_Amount *total_amount,
+ const struct TALER_PaytoHashP *wire_target_h_payto,
+ struct GNUNET_TIME_Timestamp deadline)
{
- const struct TALER_EXCHANGEDB_Deposit *deposit = cls;
+ const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = cls;
- (void) payto_uri;
+ (void) batch_deposit_serial_id;
(void) deadline;
- (void) rowid;
- if (done)
- {
- GNUNET_break (0);
- result = 66;
- }
- if (0 != TALER_amount_cmp (amount,
- &deposit->amount_with_fee))
- {
- GNUNET_break (0);
- result = 66;
- }
- if (0 != GNUNET_memcmp (coin_pub,
- &deposit->coin.coin_pub))
- {
- GNUNET_break (0);
- result = 66;
- }
+ (void) wire_target_h_payto;
+ if (0 ==
+ TALER_amount_cmp (total_amount,
+ &deposit->amount_with_fee))
+ result = 8;
}
@@ -1185,7 +1178,7 @@ run (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_TIME_Timestamp deadline;
- union TALER_DenominationBlindingKeyP coin_blind;
+ union GNUNET_CRYPTO_BlindingSecretP coin_blind;
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_ReservePublicKeyP reserve_pub2;
struct TALER_ReservePublicKeyP reserve_pub3;
@@ -1197,8 +1190,10 @@ run (void *cls)
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_EXCHANGEDB_CoinDepositInformation deposit;
+ struct TALER_EXCHANGEDB_BatchDeposit bd;
+ struct TALER_CoinSpendPublicKeyP cpub2;
+ struct TALER_MerchantPublicKeyP mpub2;
struct TALER_EXCHANGEDB_Refund refund;
struct TALER_EXCHANGEDB_TransactionList *tl;
struct TALER_EXCHANGEDB_TransactionList *tlp;
@@ -1218,17 +1213,19 @@ run (void *cls)
uint64_t reserve_out_serial_id;
uint64_t melt_serial_id;
struct TALER_PlanchetMasterSecretP ps;
- union TALER_DenominationBlindingKeyP bks;
- struct TALER_ExchangeWithdrawValues alg_values = {
- /* RSA is simpler, and for the DB there is no real difference between
- CS and RSA, just one should be used, so we use RSA */
- .cipher = TALER_DENOMINATION_RSA
- };
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+ const struct TALER_ExchangeWithdrawValues *alg_values
+ = TALER_denom_ewv_rsa_singleton ();
memset (&deposit,
0,
sizeof (deposit));
- deposit.receiver_wire_account = (char *) rcvr;
+ memset (&bd,
+ 0,
+ sizeof (bd));
+ bd.receiver_wire_account = (char *) rcvr;
+ bd.cdis = &deposit;
+ bd.num_cdis = 1;
memset (&salt,
45,
sizeof (salt));
@@ -1277,7 +1274,6 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.000010",
&fees.deposit));
- deposit.deposit_fee = fees.deposit;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.000010",
&fees.refresh));
@@ -1306,7 +1302,6 @@ run (void *cls)
plugin->reserves_in_insert (plugin->cls,
&reserve,
1,
- 1,
&qsr));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
qsr);
@@ -1333,7 +1328,6 @@ run (void *cls)
plugin->reserves_in_insert (plugin->cls,
&reserve,
1,
- 1,
&qsr));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
qsr);
@@ -1363,7 +1357,7 @@ run (void *cls)
RND_BLK (&cbc.reserve_sig);
RND_BLK (&ps);
TALER_planchet_blinding_secret_create (&ps,
- &alg_values,
+ alg_values,
&bks);
{
struct TALER_PlanchetDetail pd;
@@ -1384,15 +1378,15 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_denom_blind (&dkp->pub,
&bks,
+ NULL,
p_ah[i],
&coin_pub,
- &alg_values,
+ alg_values,
&c_hash,
&pd.blinded_planchet));
- GNUNET_assert (GNUNET_OK ==
- TALER_coin_ev_hash (&pd.blinded_planchet,
- &cbc.denom_pub_hash,
- &cbc.h_coin_envelope));
+ TALER_coin_ev_hash (&pd.blinded_planchet,
+ &cbc.denom_pub_hash,
+ &cbc.h_coin_envelope);
if (i != 0)
TALER_blinded_denom_sig_free (&cbc.sig);
GNUNET_assert (
@@ -1414,21 +1408,39 @@ run (void *cls)
{
bool found;
- bool nonce_ok;
+ bool nonce_reuse;
bool balance_ok;
+ bool age_ok;
+ bool conflict;
+ bool denom_unknown;
+ uint16_t maximum_age;
uint64_t ruuid;
+ struct TALER_Amount reserve_balance;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->do_withdraw (plugin->cls,
- NULL,
- &cbc,
- now,
- &found,
- &balance_ok,
- &nonce_ok,
- &ruuid));
+ plugin->do_batch_withdraw (plugin->cls,
+ now,
+ &reserve_pub,
+ &value,
+ true,
+ &found,
+ &balance_ok,
+ &reserve_balance,
+ &age_ok,
+ &maximum_age,
+ &ruuid));
+ FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ plugin->do_batch_withdraw_insert (plugin->cls,
+ NULL,
+ &cbc,
+ now,
+ ruuid,
+ &denom_unknown,
+ &conflict,
+ &nonce_reuse));
GNUNET_assert (found);
- GNUNET_assert (nonce_ok);
+ GNUNET_assert (! nonce_reuse);
+ GNUNET_assert (! denom_unknown);
GNUNET_assert (balance_ok);
}
@@ -1469,7 +1481,7 @@ run (void *cls)
&cbc2.sig,
&bks,
&c_hash,
- &alg_values,
+ alg_values,
&dkp->pub));
FAILIF (GNUNET_OK !=
TALER_denom_pub_verify (&dkp->pub,
@@ -1488,7 +1500,7 @@ run (void *cls)
&cbc.sig,
&bks,
&c_hash,
- &alg_values,
+ alg_values,
&dkp->pub));
deadline = GNUNET_TIME_timestamp_get ();
{
@@ -1508,23 +1520,22 @@ run (void *cls)
struct GNUNET_TIME_Timestamp deposit_timestamp
= GNUNET_TIME_timestamp_get ();
bool balance_ok;
+ uint32_t bad_balance_idx;
bool in_conflict;
struct TALER_PaytoHashP h_payto;
RND_BLK (&h_payto);
- deposit.refund_deadline
+ bd.refund_deadline
= GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
- deposit.wire_deadline
+ bd.wire_deadline
= GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
deposit.amount_with_fee = value;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->do_deposit (plugin->cls,
- &deposit,
- known_coin_id,
- &h_payto,
- false,
+ &bd,
&deposit_timestamp,
&balance_ok,
+ &bad_balance_idx,
&in_conflict));
FAILIF (! balance_ok);
FAILIF (in_conflict);
@@ -1537,9 +1548,9 @@ run (void *cls)
bool conflict;
refund.coin = deposit.coin;
- refund.details.merchant_pub = deposit.merchant_pub;
+ refund.details.merchant_pub = bd.merchant_pub;
RND_BLK (&refund.details.merchant_sig);
- refund.details.h_contract_terms = deposit.h_contract_terms;
+ refund.details.h_contract_terms = bd.h_contract_terms;
refund.details.rtransaction_id = 1;
refund.details.refund_amount = value;
refund.details.refund_fee = fees.refund;
@@ -1642,7 +1653,8 @@ run (void *cls)
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
struct GNUNET_TIME_Timestamp now;
- struct TALER_BlindedRsaPlanchet *rp;
+ struct GNUNET_CRYPTO_BlindedMessage *rp;
+ struct GNUNET_CRYPTO_RsaBlindedMessage *rsa;
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
@@ -1654,18 +1666,22 @@ run (void *cls)
new_denom_pubs[cnt] = new_dkp[cnt]->pub;
ccoin = &revealed_coins[cnt];
bp = &ccoin->blinded_planchet;
- bp->cipher = TALER_DENOMINATION_RSA;
- rp = &bp->details.rsa_blinded_planchet;
- rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
+ rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ bp->blinded_message = rp;
+ rp->cipher = GNUNET_CRYPTO_BSA_RSA;
+ rp->rc = 1;
+ rsa = &rp->details.rsa_blinded_message;
+ rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
GNUNET_CRYPTO_QUALITY_WEAK,
(RSA_KEY_SIZE / 8) - 1);
- rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size);
+ rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- rp->blinded_msg,
- rp->blinded_msg_size);
+ rsa->blinded_msg,
+ rsa->blinded_msg_size);
TALER_denom_pub_hash (&new_dkp[cnt]->pub,
&ccoin->h_denom_pub);
- ccoin->exchange_vals = alg_values;
+ TALER_denom_ewv_copy (&ccoin->exchange_vals,
+ alg_values);
TALER_coin_ev_hash (bp,
&ccoin->h_denom_pub,
&ccoin->coin_envelope_hash);
@@ -1723,11 +1739,20 @@ run (void *cls)
/* Just to test fetching a coin with melt history */
struct TALER_EXCHANGEDB_TransactionList *tl;
enum GNUNET_DB_QueryStatus qs;
+ uint64_t etag;
+ struct TALER_Amount balance;
+ struct TALER_DenominationHashP h_denom_pub;
qs = plugin->get_coin_transactions (plugin->cls,
&refresh.coin.coin_pub,
+ 0,
+ 0,
+ &etag,
+ &balance,
+ &h_denom_pub,
&tl);
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
+ FAILIF (0 >= qs);
+ FAILIF (NULL == tl);
plugin->free_coin_transaction_list (plugin->cls,
tl);
}
@@ -1737,7 +1762,7 @@ run (void *cls)
{
struct GNUNET_TIME_Timestamp recoup_timestamp
= GNUNET_TIME_timestamp_get ();
- union TALER_DenominationBlindingKeyP coin_bks;
+ union GNUNET_CRYPTO_BlindingSecretP coin_bks;
uint64_t new_known_coin_id;
struct TALER_CoinPublicInfo new_coin;
struct TALER_DenominationHashP dph;
@@ -1854,13 +1879,19 @@ run (void *cls)
0,
value.currency));
result = 7;
+ FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+ plugin->commit (plugin->cls));
/* check reserve history */
{
struct TALER_Amount balance;
+ uint64_t etag_out;
qs = plugin->get_reserve_history (plugin->cls,
&reserve_pub,
+ 0,
+ 0,
+ &etag_out,
&balance,
&rh);
}
@@ -1972,9 +2003,20 @@ run (void *cls)
&audit_refund_cb,
NULL));
FAILIF (1 != auditor_row_cnt);
- qs = plugin->get_coin_transactions (plugin->cls,
- &refund.coin.coin_pub,
- &tl);
+ {
+ uint64_t etag = 0;
+ struct TALER_Amount balance;
+ struct TALER_DenominationHashP h_denom_pub;
+
+ qs = plugin->get_coin_transactions (plugin->cls,
+ &refund.coin.coin_pub,
+ 0,
+ 0,
+ &etag,
+ &balance,
+ &h_denom_pub,
+ &tl);
+ }
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
GNUNET_assert (NULL != tl);
matched = 0;
@@ -1994,26 +2036,24 @@ run (void *cls)
&deposit.csig));
FAILIF (0 !=
GNUNET_memcmp (&have->merchant_pub,
- &deposit.merchant_pub));
+ &bd.merchant_pub));
FAILIF (0 !=
GNUNET_memcmp (&have->h_contract_terms,
- &deposit.h_contract_terms));
+ &bd.h_contract_terms));
FAILIF (0 !=
GNUNET_memcmp (&have->wire_salt,
- &deposit.wire_salt));
+ &bd.wire_salt));
FAILIF (GNUNET_TIME_timestamp_cmp (have->timestamp,
!=,
- deposit.timestamp));
+ bd.wallet_timestamp));
FAILIF (GNUNET_TIME_timestamp_cmp (have->refund_deadline,
!=,
- deposit.refund_deadline));
+ bd.refund_deadline));
FAILIF (GNUNET_TIME_timestamp_cmp (have->wire_deadline,
!=,
- deposit.wire_deadline));
+ bd.wire_deadline));
FAILIF (0 != TALER_amount_cmp (&have->amount_with_fee,
&deposit.amount_with_fee));
- FAILIF (0 != TALER_amount_cmp (&have->deposit_fee,
- &deposit.deposit_fee));
matched |= 1;
break;
}
@@ -2084,7 +2124,6 @@ run (void *cls)
memset (&deposit,
0,
sizeof (deposit));
- deposit.deposit_fee = fees.deposit;
RND_BLK (&deposit.coin.coin_pub);
TALER_denom_pub_hash (&dkp->pub,
&deposit.coin.denom_pub_hash);
@@ -2093,24 +2132,25 @@ run (void *cls)
&cbc.sig,
&bks,
&c_hash,
- &alg_values,
+ alg_values,
&dkp->pub));
RND_BLK (&deposit.csig);
- RND_BLK (&deposit.merchant_pub);
- RND_BLK (&deposit.h_contract_terms);
- RND_BLK (&deposit.wire_salt);
- deposit.receiver_wire_account =
+ RND_BLK (&bd.merchant_pub);
+ RND_BLK (&bd.h_contract_terms);
+ RND_BLK (&bd.wire_salt);
+ bd.receiver_wire_account =
"payto://iban/DE67830654080004822650?receiver-name=Test";
TALER_merchant_wire_signature_hash (
"payto://iban/DE67830654080004822650?receiver-name=Test",
- &deposit.wire_salt,
+ &bd.wire_salt,
&h_wire_wt);
deposit.amount_with_fee = value;
- deposit.deposit_fee = fees.deposit;
-
- deposit.refund_deadline = deadline;
- deposit.wire_deadline = deadline;
+ bd.refund_deadline = deadline;
+ bd.wire_deadline = deadline;
result = 8;
+ FAILIF (GNUNET_OK !=
+ plugin->start (plugin->cls,
+ "test-3"));
{
uint64_t known_coin_id;
struct TALER_DenominationHashP dph;
@@ -2128,22 +2168,30 @@ run (void *cls)
struct GNUNET_TIME_Timestamp r;
struct TALER_Amount deposit_fee;
struct TALER_MerchantWireHashP h_wire;
+ bool balance_ok;
+ uint32_t bad_idx;
+ bool ctr_conflict;
now = GNUNET_TIME_timestamp_get ();
+ TALER_payto_hash (bd.receiver_wire_account,
+ &bd.wire_target_h_payto);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->insert_deposit (plugin->cls,
- now,
- &deposit));
- TALER_merchant_wire_signature_hash (deposit.receiver_wire_account,
- &deposit.wire_salt,
+ plugin->do_deposit (plugin->cls,
+ &bd,
+ &now,
+ &balance_ok,
+ &bad_idx,
+ &ctr_conflict));
+ TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
+ &bd.wire_salt,
&h_wire);
FAILIF (1 !=
plugin->have_deposit2 (plugin->cls,
- &deposit.h_contract_terms,
+ &bd.h_contract_terms,
&h_wire,
&deposit.coin.coin_pub,
- &deposit.merchant_pub,
- deposit.refund_deadline,
+ &bd.merchant_pub,
+ bd.refund_deadline,
&deposit_fee,
&r));
FAILIF (GNUNET_TIME_timestamp_cmp (now,
@@ -2151,29 +2199,20 @@ run (void *cls)
r));
}
{
- struct GNUNET_TIME_Timestamp start_range;
- struct GNUNET_TIME_Timestamp end_range;
-
- start_range = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_subtract (deadline.abs_time,
- GNUNET_TIME_UNIT_SECONDS));
- end_range = GNUNET_TIME_absolute_to_timestamp (
- GNUNET_TIME_absolute_add (deadline.abs_time,
- GNUNET_TIME_UNIT_SECONDS));
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->select_deposits_missing_wire (plugin->cls,
- start_range,
- end_range,
- &wire_missing_cb,
- &deposit));
+ result = 66;
+ FAILIF (0 >=
+ plugin->select_batch_deposits_missing_wire (plugin->cls,
+ 0,
+ &wire_missing_cb,
+ &deposit));
FAILIF (8 != result);
}
auditor_row_cnt = 0;
FAILIF (0 >=
- plugin->select_deposits_above_serial_id (plugin->cls,
- 0,
- &audit_deposit_cb,
- NULL));
+ plugin->select_coin_deposits_above_serial_id (plugin->cls,
+ 0,
+ &audit_deposit_cb,
+ NULL));
FAILIF (0 == auditor_row_cnt);
result = 8;
sleep (2); /* give deposit time to be ready */
@@ -2188,9 +2227,9 @@ run (void *cls)
&merchant_pub2,
&payto_uri2));
FAILIF (0 != GNUNET_memcmp (&merchant_pub2,
- &deposit.merchant_pub));
+ &bd.merchant_pub));
FAILIF (0 != strcmp (payto_uri2,
- deposit.receiver_wire_account));
+ bd.receiver_wire_account));
TALER_payto_hash (payto_uri2,
&wire_target_h_payto);
GNUNET_free (payto_uri2);
@@ -2206,7 +2245,7 @@ run (void *cls)
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->aggregate (plugin->cls,
&wire_target_h_payto,
- &deposit.merchant_pub,
+ &bd.merchant_pub,
&wtid,
&total));
}
@@ -2230,7 +2269,7 @@ run (void *cls)
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->select_aggregation_transient (plugin->cls,
&wire_target_h_payto,
- &deposit.merchant_pub,
+ &bd.merchant_pub,
"x-bank",
&wtid2,
&total2));
@@ -2238,14 +2277,14 @@ run (void *cls)
plugin->create_aggregation_transient (plugin->cls,
&wire_target_h_payto,
"x-bank",
- &deposit.merchant_pub,
+ &bd.merchant_pub,
&wtid,
0,
&total));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_aggregation_transient (plugin->cls,
&wire_target_h_payto,
- &deposit.merchant_pub,
+ &bd.merchant_pub,
"x-bank",
&wtid2,
&total2));
@@ -2267,7 +2306,7 @@ run (void *cls)
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_aggregation_transient (plugin->cls,
&wire_target_h_payto,
- &deposit.merchant_pub,
+ &bd.merchant_pub,
"x-bank",
&wtid2,
&total2));
@@ -2284,7 +2323,7 @@ run (void *cls)
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->select_aggregation_transient (plugin->cls,
&wire_target_h_payto,
- &deposit.merchant_pub,
+ &bd.merchant_pub,
"x-bank",
&wtid2,
&total2));
@@ -2293,37 +2332,35 @@ run (void *cls)
plugin->commit (plugin->cls));
result = 10;
- deposit2 = deposit;
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
"test-2"));
- RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
+ RND_BLK (&mpub2); /* should fail if merchant is different */
{
struct TALER_MerchantWireHashP h_wire;
struct GNUNET_TIME_Timestamp r;
struct TALER_Amount deposit_fee;
- TALER_merchant_wire_signature_hash (deposit2.receiver_wire_account,
- &deposit2.wire_salt,
+ TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
+ &bd.wire_salt,
&h_wire);
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->have_deposit2 (plugin->cls,
- &deposit2.h_contract_terms,
+ &bd.h_contract_terms,
&h_wire,
- &deposit2.coin.coin_pub,
- &deposit2.merchant_pub,
- deposit2.refund_deadline,
+ &deposit.coin.coin_pub,
+ &mpub2,
+ bd.refund_deadline,
&deposit_fee,
&r));
- deposit2.merchant_pub = deposit.merchant_pub;
- RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
+ RND_BLK (&cpub2); /* should fail if coin is different */
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->have_deposit2 (plugin->cls,
- &deposit2.h_contract_terms,
+ &bd.h_contract_terms,
&h_wire,
- &deposit2.coin.coin_pub,
- &deposit2.merchant_pub,
- deposit2.refund_deadline,
+ &cpub2,
+ &bd.merchant_pub,
+ bd.refund_deadline,
&deposit_fee,
&r));
}
@@ -2373,7 +2410,7 @@ run (void *cls)
FAILIF (GNUNET_OK !=
test_wire_prepare ());
FAILIF (GNUNET_OK !=
- test_wire_out (&deposit));
+ test_wire_out (&bd));
FAILIF (GNUNET_OK !=
test_gc ());
FAILIF (GNUNET_OK !=
@@ -2437,8 +2474,9 @@ main (int argc,
return -1;
}
GNUNET_log_setup (argv[0],
- "WARNING",
+ "INFO",
NULL);
+ TALER_OS_init ();
plugin_name++;
(void) GNUNET_asprintf (&testname,
"test-exchange-db-%s",
diff --git a/src/exchangedb/test_exchangedb_by_j.c b/src/exchangedb/test_exchangedb_by_j.c
index 9769d964b..24b24d5b0 100644
--- a/src/exchangedb/test_exchangedb_by_j.c
+++ b/src/exchangedb/test_exchangedb_by_j.c
@@ -74,8 +74,8 @@ static void
run (void *cls)
{
static const unsigned int batches[] = {1, 2, 3, 4, 8, 16 };
- struct GNUNET_TIME_Relative times[sizeof (batches)/sizeof(*batches)];
- unsigned long long sqrs[sizeof (batches)/sizeof(*batches)];
+ struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)];
+ unsigned long long sqrs[sizeof (batches) / sizeof(*batches)];
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
@@ -101,74 +101,75 @@ run (void *cls)
memset (times, 0, sizeof (times));
memset (sqrs, 0, sizeof (sqrs));
for (unsigned int r = 0; r < ROUNDS; r++)
- {
+ {
for (unsigned int i = 0; i< 6; i++)
+ {
+ const char *sndr = "payto://x-taler-bank/localhost:8080/1";
+ struct TALER_Amount value;
+ unsigned int batch_size = batches[i];
+ unsigned int iterations = 16; // 1024*10;
+ struct TALER_ReservePublicKeyP reserve_pubs[iterations];
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp ts;
+ struct GNUNET_TIME_Relative duration;
+ struct TALER_EXCHANGEDB_ReserveInInfo reserves[iterations];
+ enum GNUNET_DB_QueryStatus results[iterations];
+ unsigned long long duration_sq;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.000010",
+ &value));
+ now = GNUNET_TIME_absolute_get ();
+ ts = GNUNET_TIME_timestamp_get ();
+ for (unsigned int r = 0; r<iterations; r++)
{
- const char *sndr = "payto://x-taler-bank/localhost:8080/1";
- struct TALER_Amount value;
- unsigned int batch_size = batches[i];
- unsigned int iterations = 16;//1024*10;
- struct TALER_ReservePublicKeyP reserve_pubs[iterations];
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Timestamp ts;
- struct GNUNET_TIME_Relative duration;
- struct TALER_EXCHANGEDB_ReserveInInfo reserves[iterations];
- enum GNUNET_DB_QueryStatus results[iterations];
- unsigned long long duration_sq;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (CURRENCY ":1.000010",
- &value));
- now = GNUNET_TIME_absolute_get ();
- ts = GNUNET_TIME_timestamp_get ();
- for (unsigned int r = 0; r<iterations; r++)
- {
- RND_BLK (&reserve_pubs[r]);
- reserves[r].reserve_pub = &reserve_pubs[r];
- reserves[r].balance = &value;
- reserves[r].execution_time = ts;
- reserves[r].sender_account_details = sndr;
- reserves[r].exchange_account_name = "name";
- reserves[r].wire_reference = r;
- }
- FAILIF (iterations !=
- plugin->batch2_reserves_in_insert (plugin->cls,
- reserves,
- iterations,
- batch_size,
- results));
- duration = GNUNET_TIME_absolute_get_duration (now);
- times[i] = GNUNET_TIME_relative_add (times[i],
- duration);
- duration_sq = duration.rel_value_us * duration.rel_value_us;
- GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us);
- GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]);
- sqrs[i] += duration_sq;
- fprintf (stdout,
- "for a batchsize equal to %d it took %s\n",
- batch_size,
- GNUNET_STRINGS_relative_time_to_string (duration,
- GNUNET_NO) );
-
- system ("./test.sh"); //DELETE AFTER TIMER
+ RND_BLK (&reserve_pubs[r]);
+ reserves[r].reserve_pub = &reserve_pubs[r];
+ reserves[r].balance = &value;
+ reserves[r].execution_time = ts;
+ reserves[r].sender_account_details = sndr;
+ reserves[r].exchange_account_name = "name";
+ reserves[r].wire_reference = r;
}
+ FAILIF (iterations !=
+ plugin->batch2_reserves_in_insert (plugin->cls,
+ reserves,
+ iterations,
+ batch_size,
+ results));
+ duration = GNUNET_TIME_absolute_get_duration (now);
+ times[i] = GNUNET_TIME_relative_add (times[i],
+ duration);
+ duration_sq = duration.rel_value_us * duration.rel_value_us;
+ GNUNET_assert (duration_sq / duration.rel_value_us ==
+ duration.rel_value_us);
+ GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]);
+ sqrs[i] += duration_sq;
+ fprintf (stdout,
+ "for a batchsize equal to %d it took %s\n",
+ batch_size,
+ GNUNET_STRINGS_relative_time_to_string (duration,
+ GNUNET_NO) );
+
+ system ("./test.sh"); // DELETE AFTER TIMER
}
- for (unsigned int i = 0; i< 6; i++)
- {
- struct GNUNET_TIME_Relative avg;
- double avg_dbl;
- double variance;
-
- avg = GNUNET_TIME_relative_divide (times[i],
- ROUNDS);
- avg_dbl = avg.rel_value_us;
- variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS);
- fprintf(stdout,
- "Batch[%2u]: %8llu ± %6.0f\n",
- batches[i],
- (unsigned long long) avg.rel_value_us,
- sqrt (variance / (ROUNDS-1)));
- }
+ }
+ for (unsigned int i = 0; i< 6; i++)
+ {
+ struct GNUNET_TIME_Relative avg;
+ double avg_dbl;
+ double variance;
+
+ avg = GNUNET_TIME_relative_divide (times[i],
+ ROUNDS);
+ avg_dbl = avg.rel_value_us;
+ variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS);
+ fprintf (stdout,
+ "Batch[%2u]: %8llu ± %6.0f\n",
+ batches[i],
+ (unsigned long long) avg.rel_value_us,
+ sqrt (variance / (ROUNDS - 1)));
+ }
result = 0;
drop:
diff --git a/src/exchangedb/test_idempotency.sh b/src/exchangedb/test_idempotency.sh
new file mode 100755
index 000000000..7314b8c3f
--- /dev/null
+++ b/src/exchangedb/test_idempotency.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# This file is in the public domain.
+set -eu
+psql talercheck < /dev/null || exit 77
+echo "Initializing DB"
+taler-exchange-dbinit -r -c test-exchange-db-postgres.conf
+echo "Re-initializing DB"
+taler-exchange-dbinit -c test-exchange-db-postgres.conf
+echo "Re-loading procedures"
+psql talercheck < procedures.sql
+echo "Test PASSED"
+exit 0
diff --git a/src/exchangedb/versioning.sql b/src/exchangedb/versioning.sql
index 116f409b7..444cf95ed 100644
--- a/src/exchangedb/versioning.sql
+++ b/src/exchangedb/versioning.sql
@@ -146,12 +146,13 @@
BEGIN;
+
-- This file adds versioning support to database it will be loaded to.
-- It requires that PL/pgSQL is already loaded - will raise exception otherwise.
-- All versioning "stuff" (tables, functions) is in "_v" schema.
-- All functions are defined as 'RETURNS SETOF INT4' to be able to make them to RETURN literally nothing (0 rows).
--- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling.
+-- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling
CREATE SCHEMA IF NOT EXISTS _v;
COMMENT ON SCHEMA _v IS 'Schema for versioning data and functionality.';