diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-08-24 22:49:35 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-08-24 22:49:35 +0200 |
commit | 71ae493c7a7601b418de4f5c83159d46abf677b8 (patch) | |
tree | 30f4438e383326d36178ed62124ca2dac1e483fd | |
parent | b5dd2bcdbb25cd6af1897b652c05d782a64dac5f (diff) | |
download | exchange-71ae493c7a7601b418de4f5c83159d46abf677b8.tar.gz exchange-71ae493c7a7601b418de4f5c83159d46abf677b8.zip |
refactor wire auditor to properly handle multiple accounts
-rw-r--r-- | src/auditor/auditor.conf | 4 | ||||
-rw-r--r-- | src/auditor/taler-wire-auditor.c | 735 | ||||
-rw-r--r-- | src/auditor/test-auditor.conf | 1 | ||||
-rw-r--r-- | src/auditordb/plugin_auditordb_postgres.c | 217 | ||||
-rw-r--r-- | src/include/taler_auditordb_plugin.h | 116 |
5 files changed, 691 insertions, 382 deletions
diff --git a/src/auditor/auditor.conf b/src/auditor/auditor.conf index c3b9a00c6..a099f9b72 100644 --- a/src/auditor/auditor.conf +++ b/src/auditor/auditor.conf | |||
@@ -4,6 +4,10 @@ | |||
4 | # Which database backend do we use for the auditor? | 4 | # Which database backend do we use for the auditor? |
5 | DB = postgres | 5 | DB = postgres |
6 | 6 | ||
7 | # Option specifying which amount is considered 'tiny' | ||
8 | # and thus doesn't need to be wire-transferred. | ||
9 | #TINY_AMOUNT = KUDOS:0.01 | ||
10 | |||
7 | # Where do we store the auditor's private key? | 11 | # Where do we store the auditor's private key? |
8 | AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv | 12 | AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv |
9 | 13 | ||
diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c index 3b84a6412..16104a64b 100644 --- a/src/auditor/taler-wire-auditor.c +++ b/src/auditor/taler-wire-auditor.c | |||
@@ -67,6 +67,31 @@ struct WireAccount | |||
67 | char *section_name; | 67 | char *section_name; |
68 | 68 | ||
69 | /** | 69 | /** |
70 | * Active wire request for the transaction history. | ||
71 | */ | ||
72 | struct TALER_WIRE_HistoryHandle *hh; | ||
73 | |||
74 | /** | ||
75 | * Progress point for this account. | ||
76 | */ | ||
77 | struct TALER_AUDITORDB_WireAccountProgressPoint pp; | ||
78 | |||
79 | /** | ||
80 | * Where we are in the inbound (CREDIT) transaction history. | ||
81 | */ | ||
82 | void *in_wire_off; | ||
83 | |||
84 | /** | ||
85 | * Where we are in the inbound (DEBIT) transaction history. | ||
86 | */ | ||
87 | void *out_wire_off; | ||
88 | |||
89 | /** | ||
90 | * Number of bytes in #in_wire_off and #out_wire_off. | ||
91 | */ | ||
92 | size_t wire_off_size; | ||
93 | |||
94 | /** | ||
70 | * We should check for inbound transactions to this account. | 95 | * We should check for inbound transactions to this account. |
71 | */ | 96 | */ |
72 | int watch_credit; | 97 | int watch_credit; |
@@ -148,22 +173,6 @@ static struct WireAccount *wa_head; | |||
148 | static struct WireAccount *wa_tail; | 173 | static struct WireAccount *wa_tail; |
149 | 174 | ||
150 | /** | 175 | /** |
151 | * Handle to the wire plugin for wire operations. | ||
152 | */ | ||
153 | static struct TALER_WIRE_Plugin *wp; | ||
154 | |||
155 | /** | ||
156 | * Name of the section that configures the account | ||
157 | * we are currently processing (matches #wp). | ||
158 | */ | ||
159 | static char *wp_section_name; | ||
160 | |||
161 | /** | ||
162 | * Active wire request for the transaction history. | ||
163 | */ | ||
164 | static struct TALER_WIRE_HistoryHandle *hh; | ||
165 | |||
166 | /** | ||
167 | * Query status for the incremental processing status in the auditordb. | 176 | * Query status for the incremental processing status in the auditordb. |
168 | */ | 177 | */ |
169 | static enum GNUNET_DB_QueryStatus qsx; | 178 | static enum GNUNET_DB_QueryStatus qsx; |
@@ -174,21 +183,6 @@ static enum GNUNET_DB_QueryStatus qsx; | |||
174 | static struct TALER_AUDITORDB_WireProgressPoint pp; | 183 | static struct TALER_AUDITORDB_WireProgressPoint pp; |
175 | 184 | ||
176 | /** | 185 | /** |
177 | * Where we are in the inbound (CREDIT) transaction history. | ||
178 | */ | ||
179 | static void *in_wire_off; | ||
180 | |||
181 | /** | ||
182 | * Where we are in the inbound (DEBIT) transaction history. | ||
183 | */ | ||
184 | static void *out_wire_off; | ||
185 | |||
186 | /** | ||
187 | * Number of bytes in #in_wire_off and #out_wire_off. | ||
188 | */ | ||
189 | static size_t wire_off_size; | ||
190 | |||
191 | /** | ||
192 | * Array of reports about row inconsitencies in wire_out table. | 186 | * Array of reports about row inconsitencies in wire_out table. |
193 | */ | 187 | */ |
194 | static json_t *report_wire_out_inconsistencies; | 188 | static json_t *report_wire_out_inconsistencies; |
@@ -226,6 +220,11 @@ static json_t *report_row_minor_inconsistencies; | |||
226 | static json_t *report_lags; | 220 | static json_t *report_lags; |
227 | 221 | ||
228 | /** | 222 | /** |
223 | * Amount that is considered "tiny" | ||
224 | */ | ||
225 | static struct TALER_Amount tiny_amount; | ||
226 | |||
227 | /** | ||
229 | * Total amount that was transferred too much from the exchange. | 228 | * Total amount that was transferred too much from the exchange. |
230 | */ | 229 | */ |
231 | static struct TALER_Amount total_bad_amount_out_plus; | 230 | static struct TALER_Amount total_bad_amount_out_plus; |
@@ -434,12 +433,6 @@ do_shutdown (void *cls) | |||
434 | report_lags = NULL; | 433 | report_lags = NULL; |
435 | report_wire_format_inconsistencies = NULL; | 434 | report_wire_format_inconsistencies = NULL; |
436 | } | 435 | } |
437 | if (NULL != hh) | ||
438 | { | ||
439 | wp->get_history_cancel (wp->cls, | ||
440 | hh); | ||
441 | hh = NULL; | ||
442 | } | ||
443 | if (NULL != in_map) | 436 | if (NULL != in_map) |
444 | { | 437 | { |
445 | GNUNET_CONTAINER_multihashmap_iterate (in_map, | 438 | GNUNET_CONTAINER_multihashmap_iterate (in_map, |
@@ -456,23 +449,23 @@ do_shutdown (void *cls) | |||
456 | GNUNET_CONTAINER_multihashmap_destroy (out_map); | 449 | GNUNET_CONTAINER_multihashmap_destroy (out_map); |
457 | out_map = NULL; | 450 | out_map = NULL; |
458 | } | 451 | } |
459 | if (NULL != wp) | ||
460 | { | ||
461 | TALER_WIRE_plugin_unload (wp); | ||
462 | wp = NULL; | ||
463 | } | ||
464 | if (NULL != wp_section_name) | ||
465 | { | ||
466 | GNUNET_free (wp_section_name); | ||
467 | wp_section_name = NULL; | ||
468 | } | ||
469 | while (NULL != (wa = wa_head)) | 452 | while (NULL != (wa = wa_head)) |
470 | { | 453 | { |
454 | if (NULL != wa->hh) | ||
455 | { | ||
456 | struct TALER_WIRE_Plugin *wp = wa->wire_plugin; | ||
457 | |||
458 | wp->get_history_cancel (wp->cls, | ||
459 | wa->hh); | ||
460 | wa->hh = NULL; | ||
461 | } | ||
471 | GNUNET_CONTAINER_DLL_remove (wa_head, | 462 | GNUNET_CONTAINER_DLL_remove (wa_head, |
472 | wa_tail, | 463 | wa_tail, |
473 | wa); | 464 | wa); |
474 | TALER_WIRE_plugin_unload (wa->wire_plugin); | 465 | TALER_WIRE_plugin_unload (wa->wire_plugin); |
475 | GNUNET_free (wa->section_name); | 466 | GNUNET_free (wa->section_name); |
467 | GNUNET_free_non_null (wa->in_wire_off); | ||
468 | GNUNET_free_non_null (wa->out_wire_off); | ||
476 | GNUNET_free (wa); | 469 | GNUNET_free (wa); |
477 | } | 470 | } |
478 | if (NULL != adb) | 471 | if (NULL != adb) |
@@ -534,25 +527,46 @@ commit (enum GNUNET_DB_QueryStatus qs) | |||
534 | esession); | 527 | esession); |
535 | return qs; | 528 | return qs; |
536 | } | 529 | } |
530 | for (struct WireAccount *wa = wa_head; | ||
531 | NULL != wa; | ||
532 | wa = wa->next) | ||
533 | { | ||
534 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx) | ||
535 | qs = adb->update_wire_auditor_account_progress (adb->cls, | ||
536 | asession, | ||
537 | &master_pub, | ||
538 | wa->section_name, | ||
539 | &wa->pp, | ||
540 | wa->in_wire_off, | ||
541 | wa->out_wire_off, | ||
542 | wa->wire_off_size); | ||
543 | else | ||
544 | qs = adb->insert_wire_auditor_account_progress (adb->cls, | ||
545 | asession, | ||
546 | &master_pub, | ||
547 | wa->section_name, | ||
548 | &wa->pp, | ||
549 | wa->in_wire_off, | ||
550 | wa->out_wire_off, | ||
551 | wa->wire_off_size); | ||
552 | if (0 >= qs) | ||
553 | { | ||
554 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
555 | "Failed to update auditor DB, not recording progress\n"); | ||
556 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | ||
557 | return qs; | ||
558 | } | ||
559 | } | ||
537 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx) | 560 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx) |
538 | qs = adb->update_wire_auditor_progress (adb->cls, | 561 | qs = adb->update_wire_auditor_progress (adb->cls, |
539 | asession, | 562 | asession, |
540 | &master_pub, | 563 | &master_pub, |
541 | wp_section_name, | 564 | &pp); |
542 | &pp, | ||
543 | in_wire_off, | ||
544 | out_wire_off, | ||
545 | wire_off_size); | ||
546 | else | 565 | else |
547 | qs = adb->insert_wire_auditor_progress (adb->cls, | 566 | qs = adb->insert_wire_auditor_progress (adb->cls, |
548 | asession, | 567 | asession, |
549 | &master_pub, | 568 | &master_pub, |
550 | wp_section_name, | 569 | &pp); |
551 | &pp, | ||
552 | in_wire_off, | ||
553 | out_wire_off, | ||
554 | wire_off_size); | ||
555 | |||
556 | if (0 >= qs) | 570 | if (0 >= qs) |
557 | { | 571 | { |
558 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 572 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
@@ -561,9 +575,8 @@ commit (enum GNUNET_DB_QueryStatus qs) | |||
561 | return qs; | 575 | return qs; |
562 | } | 576 | } |
563 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 577 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
564 | _("Concluded audit step at %llu/%llu\n"), | 578 | "Concluded audit step at %s\n", |
565 | (unsigned long long) pp.last_reserve_in_serial_id, | 579 | GNUNET_STRINGS_absolute_time_to_string (pp.last_timestamp)); |
566 | (unsigned long long) pp.last_wire_out_serial_id); | ||
567 | 580 | ||
568 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) | 581 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) |
569 | { | 582 | { |
@@ -602,16 +615,111 @@ commit (enum GNUNET_DB_QueryStatus qs) | |||
602 | } | 615 | } |
603 | 616 | ||
604 | 617 | ||
618 | /* ***************************** Analyze required transfers ************************ */ | ||
619 | |||
620 | /** | ||
621 | * Function called on deposits that are past their due date | ||
622 | * and have not yet seen a wire transfer. | ||
623 | * | ||
624 | * @param cls closure | ||
625 | * @param rowid deposit table row of the coin's deposit | ||
626 | * @param coin_pub public key of the coin | ||
627 | * @param amount value of the deposit, including fee | ||
628 | * @param wire where should the funds be wired | ||
629 | * @param deadline what was the requested wire transfer deadline | ||
630 | * @param tiny did the exchange defer this transfer because it is too small? | ||
631 | * @param done did the exchange claim that it made a transfer? | ||
632 | */ | ||
633 | static void | ||
634 | wire_missing_cb (void *cls, | ||
635 | uint64_t rowid, | ||
636 | const struct TALER_CoinSpendPublicKeyP *coin_pub, | ||
637 | const struct TALER_Amount *amount, | ||
638 | const json_t *wire, | ||
639 | struct GNUNET_TIME_Absolute deadline, | ||
640 | /* bool? */ int tiny, | ||
641 | /* bool? */ int done) | ||
642 | { | ||
643 | GNUNET_break (GNUNET_OK == | ||
644 | TALER_amount_add (&total_amount_lag, | ||
645 | &total_amount_lag, | ||
646 | amount)); | ||
647 | if ( (GNUNET_YES == tiny) && | ||
648 | (0 > TALER_amount_cmp (amount, | ||
649 | &tiny_amount)) ) | ||
650 | return; /* acceptable, amount was tiny */ | ||
651 | report (report_lags, | ||
652 | json_pack ("{s:I, s:o, s:s, s:s, s:o, s:O}", | ||
653 | "row", (json_int_t) rowid, | ||
654 | "amount", TALER_JSON_from_amount (amount), | ||
655 | "deadline", GNUNET_STRINGS_absolute_time_to_string (deadline), | ||
656 | "claimed_done", (done) ? "yes" : "no", | ||
657 | "coin_pub", GNUNET_JSON_from_data_auto (coin_pub), | ||
658 | "account", wire)); | ||
659 | |||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * Checks that all wire transfers that should have happened | ||
665 | * (based on deposits) have indeed happened. | ||
666 | * | ||
667 | * FIXME: this check _might_ rather belong with the | ||
668 | * taler-auditor logic. | ||
669 | */ | ||
670 | static void | ||
671 | check_for_required_transfers () | ||
672 | { | ||
673 | struct GNUNET_TIME_Absolute next_timestamp; | ||
674 | enum GNUNET_DB_QueryStatus qs; | ||
675 | |||
676 | next_timestamp = GNUNET_TIME_absolute_get (); | ||
677 | /* Subtract #GRACE_PERIOD, so we can be a bit behind in processing | ||
678 | without immediately raising undue concern */ | ||
679 | next_timestamp = GNUNET_TIME_absolute_subtract (next_timestamp, | ||
680 | GRACE_PERIOD); | ||
681 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
682 | "Analyzing exchange's unfinished deposits\n"); | ||
683 | qs = edb->select_deposits_missing_wire (edb->cls, | ||
684 | esession, | ||
685 | pp.last_timestamp, | ||
686 | next_timestamp, | ||
687 | &wire_missing_cb, | ||
688 | &next_timestamp); | ||
689 | if (0 > qs) | ||
690 | { | ||
691 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | ||
692 | global_ret = 1; | ||
693 | GNUNET_SCHEDULER_shutdown (); | ||
694 | return; | ||
695 | } | ||
696 | pp.last_timestamp = next_timestamp; | ||
697 | /* conclude with success */ | ||
698 | commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT); | ||
699 | } | ||
700 | |||
701 | |||
605 | /* ***************************** Analyze reserves_out ************************ */ | 702 | /* ***************************** Analyze reserves_out ************************ */ |
606 | 703 | ||
704 | /** | ||
705 | * Clean up after processing wire out data. | ||
706 | */ | ||
707 | static void | ||
708 | conclude_wire_out () | ||
709 | { | ||
710 | GNUNET_CONTAINER_multihashmap_destroy (out_map); | ||
711 | out_map = NULL; | ||
712 | check_for_required_transfers (); | ||
713 | } | ||
714 | |||
607 | 715 | ||
608 | /** | 716 | /** |
609 | * Function called with details about outgoing wire transfers | 717 | * Function called with details about outgoing wire transfers |
610 | * as claimed by the exchange DB. | 718 | * as claimed by the exchange DB. |
611 | * | 719 | * |
612 | * @param cls NULL | 720 | * @param cls a `struct WireAccount` |
613 | * @param rowid unique serial ID for the refresh session in our DB | 721 | * @param rowid unique serial ID for the refresh session in our DB |
614 | * @param date timestamp of the wire transfer (roughly) | 722 | * @param date timestamp of the transfer (roughly) |
615 | * @param wtid wire transfer subject | 723 | * @param wtid wire transfer subject |
616 | * @param wire wire transfer details of the receiver | 724 | * @param wire wire transfer details of the receiver |
617 | * @param amount amount that was wired | 725 | * @param amount amount that was wired |
@@ -625,6 +733,7 @@ wire_out_cb (void *cls, | |||
625 | const json_t *wire, | 733 | const json_t *wire, |
626 | const struct TALER_Amount *amount) | 734 | const struct TALER_Amount *amount) |
627 | { | 735 | { |
736 | struct WireAccount *wa = cls; | ||
628 | struct GNUNET_HashCode key; | 737 | struct GNUNET_HashCode key; |
629 | struct ReserveOutInfo *roi; | 738 | struct ReserveOutInfo *roi; |
630 | 739 | ||
@@ -757,6 +866,7 @@ cleanup: | |||
757 | free_roi (NULL, | 866 | free_roi (NULL, |
758 | &key, | 867 | &key, |
759 | roi)); | 868 | roi)); |
869 | wa->pp.last_wire_out_serial_id = rowid + 1; | ||
760 | return GNUNET_OK; | 870 | return GNUNET_OK; |
761 | } | 871 | } |
762 | 872 | ||
@@ -765,7 +875,7 @@ cleanup: | |||
765 | * Complain that we failed to match an entry from #out_map. This | 875 | * Complain that we failed to match an entry from #out_map. This |
766 | * means a wire transfer was made without proper justification. | 876 | * means a wire transfer was made without proper justification. |
767 | * | 877 | * |
768 | * @param cls NULL | 878 | * @param cls a `struct WireAccount` |
769 | * @param key unused key | 879 | * @param key unused key |
770 | * @param value the `struct ReserveOutInfo` to report | 880 | * @param value the `struct ReserveOutInfo` to report |
771 | * @return #GNUNET_OK | 881 | * @return #GNUNET_OK |
@@ -775,8 +885,10 @@ complain_out_not_found (void *cls, | |||
775 | const struct GNUNET_HashCode *key, | 885 | const struct GNUNET_HashCode *key, |
776 | void *value) | 886 | void *value) |
777 | { | 887 | { |
888 | struct WireAccount *wa = cls; | ||
778 | struct ReserveOutInfo *roi = value; | 889 | struct ReserveOutInfo *roi = value; |
779 | 890 | ||
891 | (void) wa; // FIXME: log which account is affected... | ||
780 | report (report_wire_out_inconsistencies, | 892 | report (report_wire_out_inconsistencies, |
781 | json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}", | 893 | json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}", |
782 | "row", (json_int_t) 0, | 894 | "row", (json_int_t) 0, |
@@ -796,84 +908,36 @@ complain_out_not_found (void *cls, | |||
796 | 908 | ||
797 | 909 | ||
798 | /** | 910 | /** |
799 | * Function called on deposits that are past their due date | 911 | * Main function for processing 'reserves_out' data. We start by going over |
800 | * and have not yet seen a wire transfer. | 912 | * the DEBIT transactions this time, and then verify that all of them are |
801 | * | 913 | * justified by 'reserves_out'. |
802 | * @param cls closure | ||
803 | * @param rowid deposit table row of the coin's deposit | ||
804 | * @param coin_pub public key of the coin | ||
805 | * @param amount value of the deposit, including fee | ||
806 | * @param wire where should the funds be wired | ||
807 | * @param deadline what was the requested wire transfer deadline | ||
808 | * @param tiny did the exchange defer this transfer because it is too small? | ||
809 | * @param done did the exchange claim that it made a transfer? | ||
810 | */ | ||
811 | static void | ||
812 | wire_missing_cb (void *cls, | ||
813 | uint64_t rowid, | ||
814 | const struct TALER_CoinSpendPublicKeyP *coin_pub, | ||
815 | const struct TALER_Amount *amount, | ||
816 | const json_t *wire, | ||
817 | struct GNUNET_TIME_Absolute deadline, | ||
818 | /* bool? */ int tiny, | ||
819 | /* bool? */ int done) | ||
820 | { | ||
821 | GNUNET_break (GNUNET_OK == | ||
822 | TALER_amount_add (&total_amount_lag, | ||
823 | &total_amount_lag, | ||
824 | amount)); | ||
825 | if (GNUNET_YES == tiny) | ||
826 | { | ||
827 | struct TALER_Amount rounded; | ||
828 | |||
829 | rounded = *amount; | ||
830 | GNUNET_break (GNUNET_SYSERR != | ||
831 | wp->amount_round (wp->cls, | ||
832 | &rounded)); | ||
833 | if (0 == TALER_amount_cmp (&rounded, | ||
834 | &zero)) | ||
835 | return; /* acceptable, amount was tiny */ | ||
836 | } | ||
837 | report (report_lags, | ||
838 | json_pack ("{s:I, s:o, s:s, s:s, s:o, s:O}", | ||
839 | "row", (json_int_t) rowid, | ||
840 | "amount", TALER_JSON_from_amount (amount), | ||
841 | "deadline", GNUNET_STRINGS_absolute_time_to_string (deadline), | ||
842 | "claimed_done", (done) ? "yes" : "no", | ||
843 | "coin_pub", GNUNET_JSON_from_data_auto (coin_pub), | ||
844 | "account", wire)); | ||
845 | |||
846 | } | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Start processing the next wire account. | ||
851 | * Shuts down if we are done. | ||
852 | * | 914 | * |
853 | * @param cls NULL | 915 | * @param cls `struct WireAccount` with a wire account list to process |
854 | */ | 916 | */ |
855 | static void | 917 | static void |
856 | process_next_account (void *cls); | 918 | process_debits (void *cls); |
857 | 919 | ||
858 | 920 | ||
859 | /** | 921 | /** |
860 | * Go over the "wire_out" table of the exchange and | 922 | * Go over the "wire_out" table of the exchange and |
861 | * verify that all wire outs are in that table. | 923 | * verify that all wire outs are in that table. |
924 | * | ||
925 | * @param wa wire account we are processing | ||
862 | */ | 926 | */ |
863 | static void | 927 | static void |
864 | check_exchange_wire_out () | 928 | check_exchange_wire_out (struct WireAccount *wa) |
865 | { | 929 | { |
866 | enum GNUNET_DB_QueryStatus qs; | 930 | enum GNUNET_DB_QueryStatus qs; |
867 | struct GNUNET_TIME_Absolute next_timestamp; | ||
868 | 931 | ||
869 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 932 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
870 | "Analyzing exchange's wire OUT table\n"); | 933 | "Analyzing exchange's wire OUT table for account `%s'\n", |
934 | wa->section_name); | ||
871 | qs = edb->select_wire_out_above_serial_id_by_account (edb->cls, | 935 | qs = edb->select_wire_out_above_serial_id_by_account (edb->cls, |
872 | esession, | 936 | esession, |
873 | wp_section_name, | 937 | wa->section_name, |
874 | pp.last_wire_out_serial_id, | 938 | wa->pp.last_wire_out_serial_id, |
875 | &wire_out_cb, | 939 | &wire_out_cb, |
876 | NULL); | 940 | wa); |
877 | if (0 > qs) | 941 | if (0 > qs) |
878 | { | 942 | { |
879 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | 943 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); |
@@ -882,41 +946,13 @@ check_exchange_wire_out () | |||
882 | return; | 946 | return; |
883 | } | 947 | } |
884 | GNUNET_CONTAINER_multihashmap_iterate (out_map, | 948 | GNUNET_CONTAINER_multihashmap_iterate (out_map, |
885 | &complain_out_not_found, | 949 | &complain_out_not_found, |
886 | NULL); | 950 | wa); |
887 | /* clean up */ | 951 | /* clean up */ |
888 | GNUNET_CONTAINER_multihashmap_iterate (out_map, | 952 | GNUNET_CONTAINER_multihashmap_iterate (out_map, |
889 | &free_roi, | 953 | &free_roi, |
890 | NULL); | 954 | NULL); |
891 | GNUNET_CONTAINER_multihashmap_destroy (out_map); | 955 | process_debits (wa->next); |
892 | out_map = NULL; | ||
893 | |||
894 | /* now check that all wire transfers that should have happened, | ||
895 | have indeed happened */ | ||
896 | next_timestamp = GNUNET_TIME_absolute_get (); | ||
897 | /* Subtract #GRACE_PERIOD, so we can be a bit behind in processing | ||
898 | without immediately raising undue concern */ | ||
899 | next_timestamp = GNUNET_TIME_absolute_subtract (next_timestamp, | ||
900 | GRACE_PERIOD); | ||
901 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
902 | "Analyzing exchange's unfinished deposits\n"); | ||
903 | qs = edb->select_deposits_missing_wire (edb->cls, | ||
904 | esession, | ||
905 | pp.last_timestamp, | ||
906 | next_timestamp, | ||
907 | &wire_missing_cb, | ||
908 | &next_timestamp); | ||
909 | if (0 > qs) | ||
910 | { | ||
911 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | ||
912 | global_ret = 1; | ||
913 | GNUNET_SCHEDULER_shutdown (); | ||
914 | return; | ||
915 | } | ||
916 | pp.last_timestamp = next_timestamp; | ||
917 | |||
918 | /* continue with next account: */ | ||
919 | process_next_account (NULL); | ||
920 | } | 956 | } |
921 | 957 | ||
922 | 958 | ||
@@ -925,7 +961,7 @@ check_exchange_wire_out () | |||
925 | * are credited to the exchange's account (incoming | 961 | * are credited to the exchange's account (incoming |
926 | * transactions). | 962 | * transactions). |
927 | * | 963 | * |
928 | * @param cls closure | 964 | * @param cls `struct WireAccount` with current wire account to process |
929 | * @param ec error code in case something went wrong | 965 | * @param ec error code in case something went wrong |
930 | * @param dir direction of the transfer | 966 | * @param dir direction of the transfer |
931 | * @param row_off identification of the position at which we are querying | 967 | * @param row_off identification of the position at which we are querying |
@@ -941,10 +977,10 @@ history_debit_cb (void *cls, | |||
941 | size_t row_off_size, | 977 | size_t row_off_size, |
942 | const struct TALER_WIRE_TransferDetails *details) | 978 | const struct TALER_WIRE_TransferDetails *details) |
943 | { | 979 | { |
980 | struct WireAccount *wa = cls; | ||
944 | struct ReserveOutInfo *roi; | 981 | struct ReserveOutInfo *roi; |
945 | struct GNUNET_HashCode rowh; | 982 | struct GNUNET_HashCode rowh; |
946 | 983 | ||
947 | |||
948 | if (TALER_BANK_DIRECTION_NONE == dir) | 984 | if (TALER_BANK_DIRECTION_NONE == dir) |
949 | { | 985 | { |
950 | if (TALER_EC_NONE != ec) | 986 | if (TALER_EC_NONE != ec) |
@@ -954,10 +990,8 @@ history_debit_cb (void *cls, | |||
954 | "Error fetching history: %u!\n", | 990 | "Error fetching history: %u!\n", |
955 | (unsigned int) ec); | 991 | (unsigned int) ec); |
956 | } | 992 | } |
957 | /* end of iteration, now check wire_out to see | 993 | wa->hh = NULL; |
958 | if it matches #out_map */ | 994 | check_exchange_wire_out (wa); |
959 | hh = NULL; | ||
960 | check_exchange_wire_out (); | ||
961 | return GNUNET_OK; | 995 | return GNUNET_OK; |
962 | } | 996 | } |
963 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 997 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
@@ -987,19 +1021,38 @@ history_debit_cb (void *cls, | |||
987 | GNUNET_free (diagnostic); | 1021 | GNUNET_free (diagnostic); |
988 | return GNUNET_OK; | 1022 | return GNUNET_OK; |
989 | } | 1023 | } |
1024 | |||
1025 | /* Update offset */ | ||
1026 | if (NULL == wa->out_wire_off) | ||
1027 | { | ||
1028 | wa->wire_off_size = row_off_size; | ||
1029 | wa->out_wire_off = GNUNET_malloc (row_off_size); | ||
1030 | } | ||
1031 | if (wa->wire_off_size != row_off_size) | ||
1032 | { | ||
1033 | GNUNET_break (0); | ||
1034 | commit (GNUNET_DB_STATUS_HARD_ERROR); | ||
1035 | wa->hh = NULL; | ||
1036 | GNUNET_SCHEDULER_shutdown (); | ||
1037 | return GNUNET_SYSERR; | ||
1038 | } | ||
1039 | memcpy (wa->out_wire_off, | ||
1040 | row_off, | ||
1041 | row_off_size); | ||
1042 | |||
990 | roi = GNUNET_new (struct ReserveOutInfo); | 1043 | roi = GNUNET_new (struct ReserveOutInfo); |
991 | GNUNET_CRYPTO_hash (&details->wtid, | 1044 | GNUNET_CRYPTO_hash (&details->wtid, |
992 | sizeof (details->wtid), | 1045 | sizeof (details->wtid), |
993 | &roi->subject_hash); | 1046 | &roi->subject_hash); |
994 | roi->details.amount = details->amount; | 1047 | roi->details.amount = details->amount; |
995 | roi->details.execution_date = details->execution_date; | 1048 | roi->details.execution_date = details->execution_date; |
996 | roi->details.wtid = details->wtid; | 1049 | roi->details.wtid = details->wtid; |
997 | roi->details.account_url = GNUNET_strdup (details->account_url); | 1050 | roi->details.account_url = GNUNET_strdup (details->account_url); |
998 | if (GNUNET_OK != | 1051 | if (GNUNET_OK != |
999 | GNUNET_CONTAINER_multihashmap_put (out_map, | 1052 | GNUNET_CONTAINER_multihashmap_put (out_map, |
1000 | &roi->subject_hash, | 1053 | &roi->subject_hash, |
1001 | roi, | 1054 | roi, |
1002 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | 1055 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) |
1003 | { | 1056 | { |
1004 | char *diagnostic; | 1057 | char *diagnostic; |
1005 | 1058 | ||
@@ -1026,31 +1079,43 @@ history_debit_cb (void *cls, | |||
1026 | 1079 | ||
1027 | 1080 | ||
1028 | /** | 1081 | /** |
1029 | * Main function for processing 'reserves_out' data. | 1082 | * Main function for processing 'reserves_out' data. We start by going over |
1030 | * We start by going over the DEBIT transactions this | 1083 | * the DEBIT transactions this time, and then verify that all of them are |
1031 | * time, and then verify that all of them are justified | 1084 | * justified by 'reserves_out'. |
1032 | * by 'reserves_out'. | 1085 | * |
1086 | * @param cls `struct WireAccount` with a wire account list to process | ||
1033 | */ | 1087 | */ |
1034 | static void | 1088 | static void |
1035 | process_debits () | 1089 | process_debits (void *cls) |
1036 | { | 1090 | { |
1091 | struct WireAccount *wa = cls; | ||
1092 | struct TALER_WIRE_Plugin *wp; | ||
1093 | |||
1094 | if (NULL == wa) | ||
1095 | { | ||
1096 | /* end of iteration, now check wire_out to see | ||
1097 | if it matches #out_map */ | ||
1098 | conclude_wire_out (); | ||
1099 | return; | ||
1100 | } | ||
1037 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1101 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1038 | "Checking bank DEBIT records\n"); | 1102 | "Checking bank DEBIT records of account `%s'\n", |
1039 | GNUNET_assert (NULL == hh); | 1103 | wa->section_name); |
1040 | out_map = GNUNET_CONTAINER_multihashmap_create (1024, | 1104 | GNUNET_assert (NULL == wa->hh); |
1041 | GNUNET_YES); | 1105 | wp = wa->wire_plugin; |
1042 | hh = wp->get_history (wp->cls, | 1106 | wa->hh = wp->get_history (wp->cls, |
1043 | wp_section_name, | 1107 | wa->section_name, |
1044 | TALER_BANK_DIRECTION_DEBIT, | 1108 | TALER_BANK_DIRECTION_DEBIT, |
1045 | out_wire_off, | 1109 | wa->out_wire_off, |
1046 | wire_off_size, | 1110 | wa->wire_off_size, |
1047 | INT64_MAX, | 1111 | INT64_MAX, |
1048 | &history_debit_cb, | 1112 | &history_debit_cb, |
1049 | NULL); | 1113 | wa); |
1050 | if (NULL == hh) | 1114 | if (NULL == wa->hh) |
1051 | { | 1115 | { |
1052 | fprintf (stderr, | 1116 | fprintf (stderr, |
1053 | "Failed to obtain bank transaction history\n"); | 1117 | "Failed to obtain bank transaction history for `%s'\n", |
1118 | wa->section_name); | ||
1054 | commit (GNUNET_DB_STATUS_HARD_ERROR); | 1119 | commit (GNUNET_DB_STATUS_HARD_ERROR); |
1055 | global_ret = 1; | 1120 | global_ret = 1; |
1056 | GNUNET_SCHEDULER_shutdown (); | 1121 | GNUNET_SCHEDULER_shutdown (); |
@@ -1059,14 +1124,40 @@ process_debits () | |||
1059 | } | 1124 | } |
1060 | 1125 | ||
1061 | 1126 | ||
1127 | /** | ||
1128 | * Begin analyzing wire_out. | ||
1129 | */ | ||
1130 | static void | ||
1131 | begin_debit_audit () | ||
1132 | { | ||
1133 | out_map = GNUNET_CONTAINER_multihashmap_create (1024, | ||
1134 | GNUNET_YES); | ||
1135 | process_debits (wa_head); | ||
1136 | } | ||
1137 | |||
1138 | |||
1062 | /* ***************************** Analyze reserves_in ************************ */ | 1139 | /* ***************************** Analyze reserves_in ************************ */ |
1063 | 1140 | ||
1141 | /** | ||
1142 | * Conclude the credit history check by logging entries that | ||
1143 | * were not found and freeing resources. Then move on to | ||
1144 | * processing debits. | ||
1145 | */ | ||
1146 | static void | ||
1147 | conclude_credit_history () | ||
1148 | { | ||
1149 | GNUNET_CONTAINER_multihashmap_destroy (in_map); | ||
1150 | in_map = NULL; | ||
1151 | /* credit done, now check debits */ | ||
1152 | begin_debit_audit (); | ||
1153 | } | ||
1154 | |||
1064 | 1155 | ||
1065 | /** | 1156 | /** |
1066 | * Function called with details about incoming wire transfers | 1157 | * Function called with details about incoming wire transfers |
1067 | * as claimed by the exchange DB. | 1158 | * as claimed by the exchange DB. |
1068 | * | 1159 | * |
1069 | * @param cls NULL | 1160 | * @param cls a `struct WireAccount` we are processing |
1070 | * @param rowid unique serial ID for the refresh session in our DB | 1161 | * @param rowid unique serial ID for the refresh session in our DB |
1071 | * @param reserve_pub public key of the reserve (also the WTID) | 1162 | * @param reserve_pub public key of the reserve (also the WTID) |
1072 | * @param credit amount that was received | 1163 | * @param credit amount that was received |
@@ -1086,6 +1177,7 @@ reserve_in_cb (void *cls, | |||
1086 | size_t wire_reference_size, | 1177 | size_t wire_reference_size, |
1087 | struct GNUNET_TIME_Absolute execution_date) | 1178 | struct GNUNET_TIME_Absolute execution_date) |
1088 | { | 1179 | { |
1180 | struct WireAccount *wa = cls; | ||
1089 | struct ReserveInInfo *rii; | 1181 | struct ReserveInInfo *rii; |
1090 | 1182 | ||
1091 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1183 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
@@ -1125,7 +1217,7 @@ reserve_in_cb (void *cls, | |||
1125 | GNUNET_free (rii); | 1217 | GNUNET_free (rii); |
1126 | return GNUNET_OK; | 1218 | return GNUNET_OK; |
1127 | } | 1219 | } |
1128 | pp.last_reserve_in_serial_id = rowid + 1; | 1220 | wa->pp.last_reserve_in_serial_id = rowid + 1; |
1129 | return GNUNET_OK; | 1221 | return GNUNET_OK; |
1130 | } | 1222 | } |
1131 | 1223 | ||
@@ -1133,7 +1225,7 @@ reserve_in_cb (void *cls, | |||
1133 | /** | 1225 | /** |
1134 | * Complain that we failed to match an entry from #in_map. | 1226 | * Complain that we failed to match an entry from #in_map. |
1135 | * | 1227 | * |
1136 | * @param cls NULL | 1228 | * @param cls a `struct WireAccount` |
1137 | * @param key unused key | 1229 | * @param key unused key |
1138 | * @param value the `struct ReserveInInfo` to free | 1230 | * @param value the `struct ReserveInInfo` to free |
1139 | * @return #GNUNET_OK | 1231 | * @return #GNUNET_OK |
@@ -1143,8 +1235,10 @@ complain_in_not_found (void *cls, | |||
1143 | const struct GNUNET_HashCode *key, | 1235 | const struct GNUNET_HashCode *key, |
1144 | void *value) | 1236 | void *value) |
1145 | { | 1237 | { |
1238 | struct WireAccount *wa = cls; | ||
1146 | struct ReserveInInfo *rii = value; | 1239 | struct ReserveInInfo *rii = value; |
1147 | 1240 | ||
1241 | (void) wa; // FIXME: log which account is affected... | ||
1148 | report (report_reserve_in_inconsistencies, | 1242 | report (report_reserve_in_inconsistencies, |
1149 | json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}", | 1243 | json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}", |
1150 | "row", (json_int_t) rii->rowid, | 1244 | "row", (json_int_t) rii->rowid, |
@@ -1162,24 +1256,13 @@ complain_in_not_found (void *cls, | |||
1162 | 1256 | ||
1163 | 1257 | ||
1164 | /** | 1258 | /** |
1165 | * Conclude the credit history check by logging entries that | 1259 | * Start processing the next wire account. |
1166 | * were not found and freeing resources. Then move on to | 1260 | * Shuts down if we are done. |
1167 | * processing debits. | 1261 | * |
1262 | * @param cls `struct WireAccount` with a wire account list to process | ||
1168 | */ | 1263 | */ |
1169 | static void | 1264 | static void |
1170 | conclude_credit_history () | 1265 | process_credits (void *cls); |
1171 | { | ||
1172 | GNUNET_CONTAINER_multihashmap_iterate (in_map, | ||
1173 | &complain_in_not_found, | ||
1174 | NULL); | ||
1175 | /* clean up before 2nd phase */ | ||
1176 | GNUNET_CONTAINER_multihashmap_iterate (in_map, | ||
1177 | &free_rii, | ||
1178 | NULL); | ||
1179 | GNUNET_CONTAINER_multihashmap_destroy (in_map); | ||
1180 | in_map = NULL; | ||
1181 | process_debits (); | ||
1182 | } | ||
1183 | 1266 | ||
1184 | 1267 | ||
1185 | /** | 1268 | /** |
@@ -1187,7 +1270,7 @@ conclude_credit_history () | |||
1187 | * are credited to the exchange's account (incoming | 1270 | * are credited to the exchange's account (incoming |
1188 | * transactions). | 1271 | * transactions). |
1189 | * | 1272 | * |
1190 | * @param cls closure | 1273 | * @param cls `struct WireAccount` we are processing |
1191 | * @param ec error code in case something went wrong | 1274 | * @param ec error code in case something went wrong |
1192 | * @param dir direction of the transfer | 1275 | * @param dir direction of the transfer |
1193 | * @param row_off identification of the position at which we are querying | 1276 | * @param row_off identification of the position at which we are querying |
@@ -1203,6 +1286,7 @@ history_credit_cb (void *cls, | |||
1203 | size_t row_off_size, | 1286 | size_t row_off_size, |
1204 | const struct TALER_WIRE_TransferDetails *details) | 1287 | const struct TALER_WIRE_TransferDetails *details) |
1205 | { | 1288 | { |
1289 | struct WireAccount *wa = cls; | ||
1206 | struct ReserveInInfo *rii; | 1290 | struct ReserveInInfo *rii; |
1207 | struct GNUNET_HashCode key; | 1291 | struct GNUNET_HashCode key; |
1208 | 1292 | ||
@@ -1216,8 +1300,18 @@ history_credit_cb (void *cls, | |||
1216 | (unsigned int) ec); | 1300 | (unsigned int) ec); |
1217 | } | 1301 | } |
1218 | /* end of operation */ | 1302 | /* end of operation */ |
1219 | hh = NULL; | 1303 | wa->hh = NULL; |
1220 | conclude_credit_history (); | 1304 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1305 | "Reconciling CREDIT processing of account `%s'\n", | ||
1306 | wa->section_name); | ||
1307 | GNUNET_CONTAINER_multihashmap_iterate (in_map, | ||
1308 | &complain_in_not_found, | ||
1309 | wa); | ||
1310 | /* clean up before 2nd phase */ | ||
1311 | GNUNET_CONTAINER_multihashmap_iterate (in_map, | ||
1312 | &free_rii, | ||
1313 | NULL); | ||
1314 | process_credits (wa->next); | ||
1221 | return GNUNET_OK; | 1315 | return GNUNET_OK; |
1222 | } | 1316 | } |
1223 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1317 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
@@ -1235,29 +1329,29 @@ history_credit_cb (void *cls, | |||
1235 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1329 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1236 | "Failed to find wire transfer at `%s' in exchange database. Audit ends at this point in time.\n", | 1330 | "Failed to find wire transfer at `%s' in exchange database. Audit ends at this point in time.\n", |
1237 | GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); | 1331 | GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); |
1238 | hh = NULL; | 1332 | wa->hh = NULL; |
1239 | conclude_credit_history (); | 1333 | process_credits (wa->next); |
1240 | return GNUNET_SYSERR; /* not an error, just end of processing */ | 1334 | return GNUNET_SYSERR; /* not an error, just end of processing */ |
1241 | } | 1335 | } |
1242 | 1336 | ||
1243 | /* Update offset */ | 1337 | /* Update offset */ |
1244 | if (NULL == in_wire_off) | 1338 | if (NULL == wa->in_wire_off) |
1245 | { | 1339 | { |
1246 | wire_off_size = row_off_size; | 1340 | wa->wire_off_size = row_off_size; |
1247 | in_wire_off = GNUNET_malloc (row_off_size); | 1341 | wa->in_wire_off = GNUNET_malloc (row_off_size); |
1248 | } | 1342 | } |
1249 | if (wire_off_size != row_off_size) | 1343 | if (wa->wire_off_size != row_off_size) |
1250 | { | 1344 | { |
1251 | GNUNET_break (0); | 1345 | GNUNET_break (0); |
1252 | commit (GNUNET_DB_STATUS_HARD_ERROR); | 1346 | commit (GNUNET_DB_STATUS_HARD_ERROR); |
1253 | GNUNET_SCHEDULER_shutdown (); | 1347 | GNUNET_SCHEDULER_shutdown (); |
1254 | hh = NULL; | ||
1255 | return GNUNET_SYSERR; | 1348 | return GNUNET_SYSERR; |
1256 | } | 1349 | } |
1257 | memcpy (in_wire_off, | 1350 | memcpy (wa->in_wire_off, |
1258 | row_off, | 1351 | row_off, |
1259 | row_off_size); | 1352 | row_off_size); |
1260 | 1353 | ||
1354 | |||
1261 | /* compare records with expected data */ | 1355 | /* compare records with expected data */ |
1262 | if (row_off_size != rii->row_off_size) | 1356 | if (row_off_size != rii->row_off_size) |
1263 | { | 1357 | { |
@@ -1384,42 +1478,83 @@ history_credit_cb (void *cls, | |||
1384 | * Start processing the next wire account. | 1478 | * Start processing the next wire account. |
1385 | * Shuts down if we are done. | 1479 | * Shuts down if we are done. |
1386 | * | 1480 | * |
1387 | * @param cls NULL | 1481 | * @param cls `struct WireAccount` with a wire account list to process |
1388 | */ | 1482 | */ |
1389 | static void | 1483 | static void |
1390 | process_next_account (void *cls) | 1484 | process_credits (void *cls) |
1391 | { | 1485 | { |
1392 | struct WireAccount *wa; | 1486 | struct WireAccount *wa = cls; |
1487 | struct TALER_WIRE_Plugin *wp; | ||
1393 | enum GNUNET_DB_QueryStatus qs; | 1488 | enum GNUNET_DB_QueryStatus qs; |
1394 | int ret; | 1489 | |
1395 | 1490 | if (NULL == wa) | |
1396 | (void) cls; | ||
1397 | // FIXME: this logic is broken at a high level, | ||
1398 | // as it iterates over the exchange's incoming | ||
1399 | // transactions once PER bank account, so for | ||
1400 | // multiple bank accounts this cannot work! | ||
1401 | if (NULL == (wa = wa_head)) | ||
1402 | { | 1491 | { |
1403 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1492 | /* done with all accounts, conclude check */ |
1404 | "Finished with all accounts, shutting down\n"); | 1493 | conclude_credit_history (); |
1405 | if (NULL != wp) | 1494 | return; |
1406 | commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT); | 1495 | } |
1496 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1497 | "Analyzing exchange's wire IN table for account `%s'\n", | ||
1498 | wa->section_name); | ||
1499 | qs = edb->select_reserves_in_above_serial_id_by_account (edb->cls, | ||
1500 | esession, | ||
1501 | wa->section_name, | ||
1502 | wa->pp.last_reserve_in_serial_id, | ||
1503 | &reserve_in_cb, | ||
1504 | wa); | ||
1505 | if (0 > qs) | ||
1506 | { | ||
1507 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | ||
1508 | global_ret = 1; | ||
1407 | GNUNET_SCHEDULER_shutdown (); | 1509 | GNUNET_SCHEDULER_shutdown (); |
1408 | return; | 1510 | return; |
1409 | } | 1511 | } |
1410 | GNUNET_CONTAINER_DLL_remove (wa_head, | 1512 | |
1411 | wa_tail, | ||
1412 | wa); | ||
1413 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1513 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1414 | "Starting audit of account `%s'\n", | 1514 | "Starting bank CREDIT history of account `%s'\n", |
1415 | wa->section_name); | 1515 | wa->section_name); |
1416 | /* setup globals */ | ||
1417 | if (NULL != wp) | ||
1418 | TALER_WIRE_plugin_unload (wp); | ||
1419 | wp = wa->wire_plugin; | 1516 | wp = wa->wire_plugin; |
1420 | GNUNET_free_non_null (wp_section_name); | 1517 | wa->hh = wp->get_history (wp->cls, |
1421 | wp_section_name = wa->section_name; | 1518 | wa->section_name, |
1422 | GNUNET_free (wa); | 1519 | TALER_BANK_DIRECTION_CREDIT, |
1520 | wa->in_wire_off, | ||
1521 | wa->wire_off_size, | ||
1522 | INT64_MAX, | ||
1523 | &history_credit_cb, | ||
1524 | wa); | ||
1525 | if (NULL == wa->hh) | ||
1526 | { | ||
1527 | fprintf (stderr, | ||
1528 | "Failed to obtain bank transaction history\n"); | ||
1529 | commit (GNUNET_DB_STATUS_HARD_ERROR); | ||
1530 | global_ret = 1; | ||
1531 | GNUNET_SCHEDULER_shutdown (); | ||
1532 | return; | ||
1533 | } | ||
1534 | } | ||
1535 | |||
1536 | |||
1537 | /** | ||
1538 | * Begin audit of CREDITs to the exchange. | ||
1539 | */ | ||
1540 | static void | ||
1541 | begin_credit_audit () | ||
1542 | { | ||
1543 | in_map = GNUNET_CONTAINER_multihashmap_create (1024, | ||
1544 | GNUNET_YES); | ||
1545 | /* now go over all bank accounts and check delta with in_map */ | ||
1546 | process_credits (wa_head); | ||
1547 | } | ||
1548 | |||
1549 | |||
1550 | /** | ||
1551 | * Start the database transactions and begin the audit. | ||
1552 | */ | ||
1553 | static void | ||
1554 | begin_transaction () | ||
1555 | { | ||
1556 | enum GNUNET_DB_QueryStatus qsx; | ||
1557 | int ret; | ||
1423 | 1558 | ||
1424 | ret = adb->start (adb->cls, | 1559 | ret = adb->start (adb->cls, |
1425 | asession); | 1560 | asession); |
@@ -1442,14 +1577,30 @@ process_next_account (void *cls) | |||
1442 | GNUNET_SCHEDULER_shutdown (); | 1577 | GNUNET_SCHEDULER_shutdown (); |
1443 | return; | 1578 | return; |
1444 | } | 1579 | } |
1580 | for (struct WireAccount *wa = wa_head; | ||
1581 | NULL != wa; | ||
1582 | wa = wa->next) | ||
1583 | { | ||
1584 | qsx = adb->get_wire_auditor_account_progress (adb->cls, | ||
1585 | asession, | ||
1586 | &master_pub, | ||
1587 | wa->section_name, | ||
1588 | &wa->pp, | ||
1589 | &wa->in_wire_off, | ||
1590 | &wa->out_wire_off, | ||
1591 | &wa->wire_off_size); | ||
1592 | if (0 > qsx) | ||
1593 | { | ||
1594 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); | ||
1595 | global_ret = 1; | ||
1596 | GNUNET_SCHEDULER_shutdown (); | ||
1597 | return; | ||
1598 | } | ||
1599 | } | ||
1445 | qsx = adb->get_wire_auditor_progress (adb->cls, | 1600 | qsx = adb->get_wire_auditor_progress (adb->cls, |
1446 | asession, | 1601 | asession, |
1447 | &master_pub, | 1602 | &master_pub, |
1448 | wp_section_name, | 1603 | &pp); |
1449 | &pp, | ||
1450 | &in_wire_off, | ||
1451 | &out_wire_off, | ||
1452 | &wire_off_size); | ||
1453 | if (0 > qsx) | 1604 | if (0 > qsx) |
1454 | { | 1605 | { |
1455 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); | 1606 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); |
@@ -1465,54 +1616,10 @@ process_next_account (void *cls) | |||
1465 | else | 1616 | else |
1466 | { | 1617 | { |
1467 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1618 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1468 | _("Resuming audit at %llu/%llu\n"), | 1619 | "Resuming audit at %s\n", |
1469 | (unsigned long long) pp.last_reserve_in_serial_id, | 1620 | GNUNET_STRINGS_absolute_time_to_string (pp.last_timestamp)); |
1470 | (unsigned long long) pp.last_wire_out_serial_id); | ||
1471 | } | ||
1472 | |||
1473 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1474 | "Analyzing exchange's wire IN table\n"); | ||
1475 | in_map = GNUNET_CONTAINER_multihashmap_create (1024, | ||
1476 | GNUNET_YES); | ||
1477 | qs = edb->select_reserves_in_above_serial_id_by_account (edb->cls, | ||
1478 | esession, | ||
1479 | wp_section_name, | ||
1480 | pp.last_reserve_in_serial_id, | ||
1481 | &reserve_in_cb, | ||
1482 | NULL); | ||
1483 | if (0 > qs) | ||
1484 | { | ||
1485 | GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); | ||
1486 | global_ret = 1; | ||
1487 | GNUNET_SCHEDULER_shutdown (); | ||
1488 | return; | ||
1489 | } | ||
1490 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) | ||
1491 | { | ||
1492 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1493 | "No new incoming transactions available, skipping CREDIT phase\n"); | ||
1494 | process_debits (); | ||
1495 | return; | ||
1496 | } | ||
1497 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1498 | "Checking bank CREDIT records\n"); | ||
1499 | hh = wp->get_history (wp->cls, | ||
1500 | wp_section_name, | ||
1501 | TALER_BANK_DIRECTION_CREDIT, | ||
1502 | in_wire_off, | ||
1503 | wire_off_size, | ||
1504 | INT64_MAX, | ||
1505 | &history_credit_cb, | ||
1506 | NULL); | ||
1507 | if (NULL == hh) | ||
1508 | { | ||
1509 | fprintf (stderr, | ||
1510 | "Failed to obtain bank transaction history\n"); | ||
1511 | commit (GNUNET_DB_STATUS_HARD_ERROR); | ||
1512 | global_ret = 1; | ||
1513 | GNUNET_SCHEDULER_shutdown (); | ||
1514 | return; | ||
1515 | } | 1621 | } |
1622 | begin_credit_audit (); | ||
1516 | } | 1623 | } |
1517 | 1624 | ||
1518 | 1625 | ||
@@ -1568,10 +1675,36 @@ run (void *cls, | |||
1568 | const struct GNUNET_CONFIGURATION_Handle *c) | 1675 | const struct GNUNET_CONFIGURATION_Handle *c) |
1569 | { | 1676 | { |
1570 | static const struct TALER_MasterPublicKeyP zeromp; | 1677 | static const struct TALER_MasterPublicKeyP zeromp; |
1678 | char *tinys; | ||
1571 | 1679 | ||
1572 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1680 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1573 | "Launching auditor\n"); | 1681 | "Launching auditor\n"); |
1574 | cfg = c; | 1682 | cfg = c; |
1683 | if (GNUNET_OK != | ||
1684 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1685 | "auditor", | ||
1686 | "TINY_AMOUNT", | ||
1687 | &tinys)) | ||
1688 | { | ||
1689 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
1690 | "auditor", | ||
1691 | "TINY_AMOUNT"); | ||
1692 | global_ret = 1; | ||
1693 | return; | ||
1694 | } | ||
1695 | if (GNUNET_OK != | ||
1696 | TALER_string_to_amount (tinys, | ||
1697 | &tiny_amount)) | ||
1698 | { | ||
1699 | GNUNET_free (tinys); | ||
1700 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, | ||
1701 | "auditor", | ||
1702 | "TINY_AMOUNT", | ||
1703 | "invalid amount"); | ||
1704 | global_ret = 1; | ||
1705 | return; | ||
1706 | } | ||
1707 | GNUNET_free (tinys); | ||
1575 | if (0 == GNUNET_memcmp (&zeromp, | 1708 | if (0 == GNUNET_memcmp (&zeromp, |
1576 | &master_pub)) | 1709 | &master_pub)) |
1577 | { | 1710 | { |
@@ -1716,7 +1849,7 @@ run (void *cls, | |||
1716 | TALER_EXCHANGEDB_find_accounts (cfg, | 1849 | TALER_EXCHANGEDB_find_accounts (cfg, |
1717 | &process_account_cb, | 1850 | &process_account_cb, |
1718 | NULL); | 1851 | NULL); |
1719 | process_next_account (NULL); | 1852 | begin_transaction (); |
1720 | } | 1853 | } |
1721 | 1854 | ||
1722 | 1855 | ||
@@ -1755,12 +1888,12 @@ main (int argc, | |||
1755 | NULL)); | 1888 | NULL)); |
1756 | if (GNUNET_OK != | 1889 | if (GNUNET_OK != |
1757 | GNUNET_PROGRAM_run (argc, | 1890 | GNUNET_PROGRAM_run (argc, |
1758 | argv, | 1891 | argv, |
1759 | "taler-wire-auditor", | 1892 | "taler-wire-auditor", |
1760 | "Audit exchange database for consistency with the bank's wire transfers", | 1893 | "Audit exchange database for consistency with the bank's wire transfers", |
1761 | options, | 1894 | options, |
1762 | &run, | 1895 | &run, |
1763 | NULL)) | 1896 | NULL)) |
1764 | return 1; | 1897 | return 1; |
1765 | return global_ret; | 1898 | return global_ret; |
1766 | } | 1899 | } |
diff --git a/src/auditor/test-auditor.conf b/src/auditor/test-auditor.conf index 781cbbce2..420b68baf 100644 --- a/src/auditor/test-auditor.conf +++ b/src/auditor/test-auditor.conf | |||
@@ -1,5 +1,6 @@ | |||
1 | [auditor] | 1 | [auditor] |
2 | DB = postgres | 2 | DB = postgres |
3 | TINY_AMOUNT = TESTKUDOS:0.01 | ||
3 | 4 | ||
4 | [auditordb-postgres] | 5 | [auditordb-postgres] |
5 | CONFIG = postgres:///taler-auditor-test | 6 | CONFIG = postgres:///taler-auditor-test |
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c index dfd8d64e0..f1eaa6f2c 100644 --- a/src/auditordb/plugin_auditordb_postgres.c +++ b/src/auditordb/plugin_auditordb_postgres.c | |||
@@ -177,6 +177,7 @@ postgres_drop_tables (void *cls, | |||
177 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_progress_deposit_confirmation;"), | 177 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_progress_deposit_confirmation;"), |
178 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_progress_coin;"), | 178 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS auditor_progress_coin;"), |
179 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS wire_auditor_progress;"), | 179 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS wire_auditor_progress;"), |
180 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS wire_auditor_account_progress;"), | ||
180 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS deposit_confirmations CASCADE;"), | 181 | GNUNET_PQ_make_execute ("DROP TABLE IF EXISTS deposit_confirmations CASCADE;"), |
181 | GNUNET_PQ_EXECUTE_STATEMENT_END | 182 | GNUNET_PQ_EXECUTE_STATEMENT_END |
182 | }; | 183 | }; |
@@ -283,15 +284,18 @@ postgres_create_tables (void *cls) | |||
283 | ",last_payback_serial_id INT8 NOT NULL DEFAULT 0" | 284 | ",last_payback_serial_id INT8 NOT NULL DEFAULT 0" |
284 | ",last_payback_refresh_serial_id INT8 NOT NULL DEFAULT 0" | 285 | ",last_payback_refresh_serial_id INT8 NOT NULL DEFAULT 0" |
285 | ")"), | 286 | ")"), |
286 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_progress" | 287 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_account_progress" |
287 | "(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE" | 288 | "(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE" |
288 | ",account_name TEXT NOT NULL" | 289 | ",account_name TEXT NOT NULL" |
289 | ",last_wire_reserve_in_serial_id INT8 NOT NULL DEFAULT 0" | 290 | ",last_wire_reserve_in_serial_id INT8 NOT NULL DEFAULT 0" |
290 | ",last_wire_wire_out_serial_id INT8 NOT NULL DEFAULT 0" | 291 | ",last_wire_wire_out_serial_id INT8 NOT NULL DEFAULT 0" |
291 | ",last_timestamp INT8 NOT NULL" | ||
292 | ",wire_in_off BYTEA" | 292 | ",wire_in_off BYTEA" |
293 | ",wire_out_off BYTEA" | 293 | ",wire_out_off BYTEA" |
294 | ")"), | 294 | ")"), |
295 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_progress" | ||
296 | "(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE" | ||
297 | ",last_timestamp INT8 NOT NULL" | ||
298 | ")"), | ||
295 | /* Table with all of the customer reserves and their respective | 299 | /* Table with all of the customer reserves and their respective |
296 | balances that the auditor is aware of. | 300 | balances that the auditor is aware of. |
297 | "last_reserve_out_serial_id" marks the last withdrawal from | 301 | "last_reserve_out_serial_id" marks the last withdrawal from |
@@ -686,39 +690,56 @@ postgres_prepare (PGconn *db_conn) | |||
686 | ",last_payback_refresh_serial_id" | 690 | ",last_payback_refresh_serial_id" |
687 | ") VALUES ($1,$2,$3,$4,$5,$6,$7);", | 691 | ") VALUES ($1,$2,$3,$4,$5,$6,$7);", |
688 | 7), | 692 | 7), |
689 | /* Used in #postgres_insert_wire_auditor_progress() */ | 693 | /* Used in #postgres_insert_wire_auditor_account_progress() */ |
690 | GNUNET_PQ_make_prepare ("wire_auditor_progress_insert", | 694 | GNUNET_PQ_make_prepare ("wire_auditor_account_progress_insert", |
691 | "INSERT INTO wire_auditor_progress " | 695 | "INSERT INTO wire_auditor_account_progress " |
692 | "(master_pub" | 696 | "(master_pub" |
693 | ",account_name" | 697 | ",account_name" |
694 | ",last_wire_reserve_in_serial_id" | 698 | ",last_wire_reserve_in_serial_id" |
695 | ",last_wire_wire_out_serial_id" | 699 | ",last_wire_wire_out_serial_id" |
696 | ",last_timestamp" | ||
697 | ",wire_in_off" | 700 | ",wire_in_off" |
698 | ",wire_out_off" | 701 | ",wire_out_off" |
699 | ") VALUES ($1,$2,$3,$4,$5,$6,$7);", | 702 | ") VALUES ($1,$2,$3,$4,$5,$6);", |
700 | 7), | 703 | 6), |
701 | /* Used in #postgres_update_wire_auditor_progress() */ | 704 | /* Used in #postgres_update_wire_auditor_account_progress() */ |
702 | GNUNET_PQ_make_prepare ("wire_auditor_progress_update", | 705 | GNUNET_PQ_make_prepare ("wire_auditor_account_progress_update", |
703 | "UPDATE wire_auditor_progress SET " | 706 | "UPDATE wire_auditor_account_progress SET " |
704 | " last_wire_reserve_in_serial_id=$1" | 707 | " last_wire_reserve_in_serial_id=$1" |
705 | ",last_wire_wire_out_serial_id=$2" | 708 | ",last_wire_wire_out_serial_id=$2" |
706 | ",last_timestamp=$3" | 709 | ",wire_in_off=$3" |
707 | ",wire_in_off=$4" | 710 | ",wire_out_off=$4" |
708 | ",wire_out_off=$5" | 711 | " WHERE master_pub=$5 AND account_name=$6", |
709 | " WHERE master_pub=$6 AND account_name=$7", | 712 | 6), |
710 | 7), | 713 | /* Used in #postgres_get_wire_auditor_account_progress() */ |
711 | /* Used in #postgres_get_wire_auditor_progress() */ | 714 | GNUNET_PQ_make_prepare ("wire_auditor_account_progress_select", |
712 | GNUNET_PQ_make_prepare ("wire_auditor_progress_select", | ||
713 | "SELECT" | 715 | "SELECT" |
714 | " last_wire_reserve_in_serial_id" | 716 | " last_wire_reserve_in_serial_id" |
715 | ",last_wire_wire_out_serial_id" | 717 | ",last_wire_wire_out_serial_id" |
716 | ",last_timestamp" | ||
717 | ",wire_in_off" | 718 | ",wire_in_off" |
718 | ",wire_out_off" | 719 | ",wire_out_off" |
719 | " FROM wire_auditor_progress" | 720 | " FROM wire_auditor_account_progress" |
720 | " WHERE master_pub=$1 AND account_name=$2;", | 721 | " WHERE master_pub=$1 AND account_name=$2;", |
721 | 2), | 722 | 2), |
723 | /* Used in #postgres_insert_wire_auditor_progress() */ | ||
724 | GNUNET_PQ_make_prepare ("wire_auditor_progress_insert", | ||
725 | "INSERT INTO wire_auditor_progress " | ||
726 | "(master_pub" | ||
727 | ",last_timestamp" | ||
728 | ") VALUES ($1,$2);", | ||
729 | 2), | ||
730 | /* Used in #postgres_update_wire_auditor_progress() */ | ||
731 | GNUNET_PQ_make_prepare ("wire_auditor_progress_update", | ||
732 | "UPDATE wire_auditor_progress SET " | ||
733 | " last_timestamp=$1" | ||
734 | " WHERE master_pub=$2", | ||
735 | 2), | ||
736 | /* Used in #postgres_get_wire_auditor_progress() */ | ||
737 | GNUNET_PQ_make_prepare ("wire_auditor_progress_select", | ||
738 | "SELECT" | ||
739 | " last_timestamp" | ||
740 | " FROM wire_auditor_progress" | ||
741 | " WHERE master_pub=$1;", | ||
742 | 1), | ||
722 | /* Used in #postgres_insert_reserve_info() */ | 743 | /* Used in #postgres_insert_reserve_info() */ |
723 | GNUNET_PQ_make_prepare ("auditor_reserves_insert", | 744 | GNUNET_PQ_make_prepare ("auditor_reserves_insert", |
724 | "INSERT INTO auditor_reserves " | 745 | "INSERT INTO auditor_reserves " |
@@ -2105,25 +2126,23 @@ postgres_get_auditor_progress_coin (void *cls, | |||
2105 | * @param session connection to use | 2126 | * @param session connection to use |
2106 | * @param master_pub master key of the exchange | 2127 | * @param master_pub master key of the exchange |
2107 | * @param account_name name of the wire account we are auditing | 2128 | * @param account_name name of the wire account we are auditing |
2108 | * @param pp where is the auditor in processing | ||
2109 | * @return transaction status code | 2129 | * @return transaction status code |
2110 | */ | 2130 | */ |
2111 | static enum GNUNET_DB_QueryStatus | 2131 | static enum GNUNET_DB_QueryStatus |
2112 | postgres_insert_wire_auditor_progress (void *cls, | 2132 | postgres_insert_wire_auditor_account_progress (void *cls, |
2113 | struct TALER_AUDITORDB_Session *session, | 2133 | struct TALER_AUDITORDB_Session *session, |
2114 | const struct TALER_MasterPublicKeyP *master_pub, | 2134 | const struct TALER_MasterPublicKeyP *master_pub, |
2115 | const char *account_name, | 2135 | const char *account_name, |
2116 | const struct TALER_AUDITORDB_WireProgressPoint *pp, | 2136 | const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, |
2117 | const void *in_wire_off, | 2137 | const void *in_wire_off, |
2118 | const void *out_wire_off, | 2138 | const void *out_wire_off, |
2119 | size_t wire_off_size) | 2139 | size_t wire_off_size) |
2120 | { | 2140 | { |
2121 | struct GNUNET_PQ_QueryParam params[] = { | 2141 | struct GNUNET_PQ_QueryParam params[] = { |
2122 | GNUNET_PQ_query_param_auto_from_type (master_pub), | 2142 | GNUNET_PQ_query_param_auto_from_type (master_pub), |
2123 | GNUNET_PQ_query_param_string (account_name), | 2143 | GNUNET_PQ_query_param_string (account_name), |
2124 | GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id), | 2144 | GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id), |
2125 | GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), | 2145 | GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), |
2126 | TALER_PQ_query_param_absolute_time (&pp->last_timestamp), | ||
2127 | GNUNET_PQ_query_param_fixed_size (in_wire_off, | 2146 | GNUNET_PQ_query_param_fixed_size (in_wire_off, |
2128 | wire_off_size), | 2147 | wire_off_size), |
2129 | GNUNET_PQ_query_param_fixed_size (out_wire_off, | 2148 | GNUNET_PQ_query_param_fixed_size (out_wire_off, |
@@ -2132,7 +2151,7 @@ postgres_insert_wire_auditor_progress (void *cls, | |||
2132 | }; | 2151 | }; |
2133 | 2152 | ||
2134 | return GNUNET_PQ_eval_prepared_non_select (session->conn, | 2153 | return GNUNET_PQ_eval_prepared_non_select (session->conn, |
2135 | "wire_auditor_progress_insert", | 2154 | "wire_auditor_account_progress_insert", |
2136 | params); | 2155 | params); |
2137 | } | 2156 | } |
2138 | 2157 | ||
@@ -2145,23 +2164,21 @@ postgres_insert_wire_auditor_progress (void *cls, | |||
2145 | * @param session connection to use | 2164 | * @param session connection to use |
2146 | * @param master_pub master key of the exchange | 2165 | * @param master_pub master key of the exchange |
2147 | * @param account_name name of the wire account we are auditing | 2166 | * @param account_name name of the wire account we are auditing |
2148 | * @param pp where is the auditor in processing | ||
2149 | * @return transaction status code | 2167 | * @return transaction status code |
2150 | */ | 2168 | */ |
2151 | static enum GNUNET_DB_QueryStatus | 2169 | static enum GNUNET_DB_QueryStatus |
2152 | postgres_update_wire_auditor_progress (void *cls, | 2170 | postgres_update_wire_auditor_account_progress (void *cls, |
2153 | struct TALER_AUDITORDB_Session *session, | 2171 | struct TALER_AUDITORDB_Session *session, |
2154 | const struct TALER_MasterPublicKeyP *master_pub, | 2172 | const struct TALER_MasterPublicKeyP *master_pub, |
2155 | const char *account_name, | 2173 | const char *account_name, |
2156 | const struct TALER_AUDITORDB_WireProgressPoint *pp, | 2174 | const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, |
2157 | const void *in_wire_off, | 2175 | const void *in_wire_off, |
2158 | const void *out_wire_off, | 2176 | const void *out_wire_off, |
2159 | size_t wire_off_size) | 2177 | size_t wire_off_size) |
2160 | { | 2178 | { |
2161 | struct GNUNET_PQ_QueryParam params[] = { | 2179 | struct GNUNET_PQ_QueryParam params[] = { |
2162 | GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id), | 2180 | GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id), |
2163 | GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), | 2181 | GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), |
2164 | TALER_PQ_query_param_absolute_time (&pp->last_timestamp), | ||
2165 | GNUNET_PQ_query_param_fixed_size (in_wire_off, | 2182 | GNUNET_PQ_query_param_fixed_size (in_wire_off, |
2166 | wire_off_size), | 2183 | wire_off_size), |
2167 | GNUNET_PQ_query_param_fixed_size (out_wire_off, | 2184 | GNUNET_PQ_query_param_fixed_size (out_wire_off, |
@@ -2172,7 +2189,7 @@ postgres_update_wire_auditor_progress (void *cls, | |||
2172 | }; | 2189 | }; |
2173 | 2190 | ||
2174 | return GNUNET_PQ_eval_prepared_non_select (session->conn, | 2191 | return GNUNET_PQ_eval_prepared_non_select (session->conn, |
2175 | "wire_auditor_progress_update", | 2192 | "wire_auditor_account_progress_update", |
2176 | params); | 2193 | params); |
2177 | } | 2194 | } |
2178 | 2195 | ||
@@ -2184,18 +2201,21 @@ postgres_update_wire_auditor_progress (void *cls, | |||
2184 | * @param session connection to use | 2201 | * @param session connection to use |
2185 | * @param master_pub master key of the exchange | 2202 | * @param master_pub master key of the exchange |
2186 | * @param account_name name of the wire account we are auditing | 2203 | * @param account_name name of the wire account we are auditing |
2187 | * @param[out] pp set to where the auditor is in processing | 2204 | * @param[out] pp where is the auditor in processing |
2205 | * @param[out] in_wire_off how far are we in the incoming wire transaction history | ||
2206 | * @param[out] out_wire_off how far are we in the outgoing wire transaction history | ||
2207 | * @param[out] wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take? | ||
2188 | * @return transaction status code | 2208 | * @return transaction status code |
2189 | */ | 2209 | */ |
2190 | static enum GNUNET_DB_QueryStatus | 2210 | static enum GNUNET_DB_QueryStatus |
2191 | postgres_get_wire_auditor_progress (void *cls, | 2211 | postgres_get_wire_auditor_account_progress (void *cls, |
2192 | struct TALER_AUDITORDB_Session *session, | 2212 | struct TALER_AUDITORDB_Session *session, |
2193 | const struct TALER_MasterPublicKeyP *master_pub, | 2213 | const struct TALER_MasterPublicKeyP *master_pub, |
2194 | const char *account_name, | 2214 | const char *account_name, |
2195 | struct TALER_AUDITORDB_WireProgressPoint *pp, | 2215 | struct TALER_AUDITORDB_WireAccountProgressPoint *pp, |
2196 | void **in_wire_off, | 2216 | void **in_wire_off, |
2197 | void **out_wire_off, | 2217 | void **out_wire_off, |
2198 | size_t *wire_off_size) | 2218 | size_t *wire_off_size) |
2199 | { | 2219 | { |
2200 | size_t xsize; | 2220 | size_t xsize; |
2201 | enum GNUNET_DB_QueryStatus qs; | 2221 | enum GNUNET_DB_QueryStatus qs; |
@@ -2209,8 +2229,6 @@ postgres_get_wire_auditor_progress (void *cls, | |||
2209 | &pp->last_reserve_in_serial_id), | 2229 | &pp->last_reserve_in_serial_id), |
2210 | GNUNET_PQ_result_spec_uint64 ("last_wire_wire_out_serial_id", | 2230 | GNUNET_PQ_result_spec_uint64 ("last_wire_wire_out_serial_id", |
2211 | &pp->last_wire_out_serial_id), | 2231 | &pp->last_wire_out_serial_id), |
2212 | TALER_PQ_result_spec_absolute_time ("last_timestamp", | ||
2213 | &pp->last_timestamp), | ||
2214 | GNUNET_PQ_result_spec_variable_size ("wire_in_off", | 2232 | GNUNET_PQ_result_spec_variable_size ("wire_in_off", |
2215 | in_wire_off, | 2233 | in_wire_off, |
2216 | wire_off_size), | 2234 | wire_off_size), |
@@ -2221,7 +2239,7 @@ postgres_get_wire_auditor_progress (void *cls, | |||
2221 | }; | 2239 | }; |
2222 | 2240 | ||
2223 | qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn, | 2241 | qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn, |
2224 | "wire_auditor_progress_select", | 2242 | "wire_auditor_account_progress_select", |
2225 | params, | 2243 | params, |
2226 | rs); | 2244 | rs); |
2227 | if (qs <= 0) | 2245 | if (qs <= 0) |
@@ -2235,6 +2253,94 @@ postgres_get_wire_auditor_progress (void *cls, | |||
2235 | 2253 | ||
2236 | 2254 | ||
2237 | /** | 2255 | /** |
2256 | * Insert information about the auditor's progress with an exchange's | ||
2257 | * data. | ||
2258 | * | ||
2259 | * @param cls the @e cls of this struct with the plugin-specific state | ||
2260 | * @param session connection to use | ||
2261 | * @param master_pub master key of the exchange | ||
2262 | * @param pp where is the auditor in processing | ||
2263 | * @return transaction status code | ||
2264 | */ | ||
2265 | static enum GNUNET_DB_QueryStatus | ||
2266 | postgres_insert_wire_auditor_progress (void *cls, | ||
2267 | struct TALER_AUDITORDB_Session *session, | ||
2268 | const struct TALER_MasterPublicKeyP *master_pub, | ||
2269 | const struct TALER_AUDITORDB_WireProgressPoint *pp) | ||
2270 | { | ||
2271 | struct GNUNET_PQ_QueryParam params[] = { | ||
2272 | GNUNET_PQ_query_param_auto_from_type (master_pub), | ||
2273 | TALER_PQ_query_param_absolute_time (&pp->last_timestamp), | ||
2274 | GNUNET_PQ_query_param_end | ||
2275 | }; | ||
2276 | |||
2277 | return GNUNET_PQ_eval_prepared_non_select (session->conn, | ||
2278 | "wire_auditor_progress_insert", | ||
2279 | params); | ||
2280 | } | ||
2281 | |||
2282 | |||
2283 | /** | ||
2284 | * Update information about the progress of the auditor. There | ||
2285 | * must be an existing record for the exchange. | ||
2286 | * | ||
2287 | * @param cls the @e cls of this struct with the plugin-specific state | ||
2288 | * @param session connection to use | ||
2289 | * @param master_pub master key of the exchange | ||
2290 | * @param pp where is the auditor in processing | ||
2291 | * @return transaction status code | ||
2292 | */ | ||
2293 | static enum GNUNET_DB_QueryStatus | ||
2294 | postgres_update_wire_auditor_progress (void *cls, | ||
2295 | struct TALER_AUDITORDB_Session *session, | ||
2296 | const struct TALER_MasterPublicKeyP *master_pub, | ||
2297 | const struct TALER_AUDITORDB_WireProgressPoint *pp) | ||
2298 | { | ||
2299 | struct GNUNET_PQ_QueryParam params[] = { | ||
2300 | TALER_PQ_query_param_absolute_time (&pp->last_timestamp), | ||
2301 | GNUNET_PQ_query_param_auto_from_type (master_pub), | ||
2302 | GNUNET_PQ_query_param_end | ||
2303 | }; | ||
2304 | |||
2305 | return GNUNET_PQ_eval_prepared_non_select (session->conn, | ||
2306 | "wire_auditor_progress_update", | ||
2307 | params); | ||
2308 | } | ||
2309 | |||
2310 | |||
2311 | /** | ||
2312 | * Get information about the progress of the auditor. | ||
2313 | * | ||
2314 | * @param cls the @e cls of this struct with the plugin-specific state | ||
2315 | * @param session connection to use | ||
2316 | * @param master_pub master key of the exchange | ||
2317 | * @param[out] pp set to where the auditor is in processing | ||
2318 | * @return transaction status code | ||
2319 | */ | ||
2320 | static enum GNUNET_DB_QueryStatus | ||
2321 | postgres_get_wire_auditor_progress (void *cls, | ||
2322 | struct TALER_AUDITORDB_Session *session, | ||
2323 | const struct TALER_MasterPublicKeyP *master_pub, | ||
2324 | struct TALER_AUDITORDB_WireProgressPoint *pp) | ||
2325 | { | ||
2326 | struct GNUNET_PQ_QueryParam params[] = { | ||
2327 | GNUNET_PQ_query_param_auto_from_type (master_pub), | ||
2328 | GNUNET_PQ_query_param_end | ||
2329 | }; | ||
2330 | struct GNUNET_PQ_ResultSpec rs[] = { | ||
2331 | TALER_PQ_result_spec_absolute_time ("last_timestamp", | ||
2332 | &pp->last_timestamp), | ||
2333 | GNUNET_PQ_result_spec_end | ||
2334 | }; | ||
2335 | |||
2336 | return GNUNET_PQ_eval_prepared_singleton_select (session->conn, | ||
2337 | "wire_auditor_progress_select", | ||
2338 | params, | ||
2339 | rs); | ||
2340 | } | ||
2341 | |||
2342 | |||
2343 | /** | ||
2238 | * Insert information about a reserve. There must not be an | 2344 | * Insert information about a reserve. There must not be an |
2239 | * existing record for the reserve. | 2345 | * existing record for the reserve. |
2240 | * | 2346 | * |
@@ -3329,6 +3435,9 @@ libtaler_plugin_auditordb_postgres_init (void *cls) | |||
3329 | plugin->update_auditor_progress_coin = &postgres_update_auditor_progress_coin; | 3435 | plugin->update_auditor_progress_coin = &postgres_update_auditor_progress_coin; |
3330 | plugin->insert_auditor_progress_coin = &postgres_insert_auditor_progress_coin; | 3436 | plugin->insert_auditor_progress_coin = &postgres_insert_auditor_progress_coin; |
3331 | 3437 | ||
3438 | plugin->get_wire_auditor_account_progress = &postgres_get_wire_auditor_account_progress; | ||
3439 | plugin->update_wire_auditor_account_progress = &postgres_update_wire_auditor_account_progress; | ||
3440 | plugin->insert_wire_auditor_account_progress = &postgres_insert_wire_auditor_account_progress; | ||
3332 | plugin->get_wire_auditor_progress = &postgres_get_wire_auditor_progress; | 3441 | plugin->get_wire_auditor_progress = &postgres_get_wire_auditor_progress; |
3333 | plugin->update_wire_auditor_progress = &postgres_update_wire_auditor_progress; | 3442 | plugin->update_wire_auditor_progress = &postgres_update_wire_auditor_progress; |
3334 | plugin->insert_wire_auditor_progress = &postgres_insert_wire_auditor_progress; | 3443 | plugin->insert_wire_auditor_progress = &postgres_insert_wire_auditor_progress; |
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h index dab548e6e..98fce62df 100644 --- a/src/include/taler_auditordb_plugin.h +++ b/src/include/taler_auditordb_plugin.h | |||
@@ -108,6 +108,21 @@ typedef int | |||
108 | */ | 108 | */ |
109 | struct TALER_AUDITORDB_WireProgressPoint | 109 | struct TALER_AUDITORDB_WireProgressPoint |
110 | { | 110 | { |
111 | |||
112 | /** | ||
113 | * Time until which we have confirmed that all wire transactions | ||
114 | * that the exchange should do, have indeed been done. | ||
115 | */ | ||
116 | struct GNUNET_TIME_Absolute last_timestamp; | ||
117 | }; | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Structure for remembering the wire auditor's progress over the | ||
122 | * various tables and (auditor) transactions per wire account. | ||
123 | */ | ||
124 | struct TALER_AUDITORDB_WireAccountProgressPoint | ||
125 | { | ||
111 | /** | 126 | /** |
112 | * serial ID of the last reserve_in transfer the wire auditor processed | 127 | * serial ID of the last reserve_in transfer the wire auditor processed |
113 | */ | 128 | */ |
@@ -118,11 +133,6 @@ struct TALER_AUDITORDB_WireProgressPoint | |||
118 | */ | 133 | */ |
119 | uint64_t last_wire_out_serial_id; | 134 | uint64_t last_wire_out_serial_id; |
120 | 135 | ||
121 | /** | ||
122 | * Time until which we have confirmed that all wire transactions | ||
123 | * that the exchange should do, have indeed been done. | ||
124 | */ | ||
125 | struct GNUNET_TIME_Absolute last_timestamp; | ||
126 | }; | 136 | }; |
127 | 137 | ||
128 | 138 | ||
@@ -801,14 +811,14 @@ struct TALER_AUDITORDB_Plugin | |||
801 | * @return transaction status code | 811 | * @return transaction status code |
802 | */ | 812 | */ |
803 | enum GNUNET_DB_QueryStatus | 813 | enum GNUNET_DB_QueryStatus |
804 | (*insert_wire_auditor_progress)(void *cls, | 814 | (*insert_wire_auditor_account_progress)(void *cls, |
805 | struct TALER_AUDITORDB_Session *session, | 815 | struct TALER_AUDITORDB_Session *session, |
806 | const struct TALER_MasterPublicKeyP *master_pub, | 816 | const struct TALER_MasterPublicKeyP *master_pub, |
807 | const char *account_name, | 817 | const char *account_name, |
808 | const struct TALER_AUDITORDB_WireProgressPoint *pp, | 818 | const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, |
809 | const void *in_wire_off, | 819 | const void *in_wire_off, |
810 | const void *out_wire_off, | 820 | const void *out_wire_off, |
811 | size_t wire_off_size); | 821 | size_t wire_off_size); |
812 | 822 | ||
813 | 823 | ||
814 | /** | 824 | /** |
@@ -826,16 +836,75 @@ struct TALER_AUDITORDB_Plugin | |||
826 | * @return transaction status code | 836 | * @return transaction status code |
827 | */ | 837 | */ |
828 | enum GNUNET_DB_QueryStatus | 838 | enum GNUNET_DB_QueryStatus |
829 | (*update_wire_auditor_progress)(void *cls, | 839 | (*update_wire_auditor_account_progress)(void *cls, |
840 | struct TALER_AUDITORDB_Session *session, | ||
841 | const struct TALER_MasterPublicKeyP *master_pub, | ||
842 | const char *account_name, | ||
843 | const struct TALER_AUDITORDB_WireAccountProgressPoint *pp, | ||
844 | const void *in_wire_off, | ||
845 | const void *out_wire_off, | ||
846 | size_t wire_off_size); | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Get information about the progress of the wire auditor. | ||
851 | * | ||
852 | * @param cls the @e cls of this struct with the plugin-specific state | ||
853 | * @param session connection to use | ||
854 | * @param master_pub master key of the exchange | ||
855 | * @param account_name name of the wire account we are auditing | ||
856 | * @param[out] pp where is the auditor in processing | ||
857 | * @param[out] in_wire_off how far are we in the incoming wire transaction history | ||
858 | * @param[out] out_wire_off how far are we in the outgoing wire transaction history | ||
859 | * @param[out] wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take? | ||
860 | * @return transaction status code | ||
861 | */ | ||
862 | enum GNUNET_DB_QueryStatus | ||
863 | (*get_wire_auditor_account_progress)(void *cls, | ||
864 | struct TALER_AUDITORDB_Session *session, | ||
865 | const struct TALER_MasterPublicKeyP *master_pub, | ||
866 | const char *account_name, | ||
867 | struct TALER_AUDITORDB_WireAccountProgressPoint *pp, | ||
868 | void **in_wire_off, | ||
869 | void **out_wire_off, | ||
870 | size_t *wire_off_size); | ||
871 | |||
872 | |||
873 | /** | ||
874 | * Insert information about the wire auditor's progress with an exchange's | ||
875 | * data. | ||
876 | * | ||
877 | * @param cls the @e cls of this struct with the plugin-specific state | ||
878 | * @param session connection to use | ||
879 | * @param master_pub master key of the exchange | ||
880 | * @param account_name name of the wire account we are auditing | ||
881 | * @param pp where is the auditor in processing | ||
882 | * @return transaction status code | ||
883 | */ | ||
884 | enum GNUNET_DB_QueryStatus | ||
885 | (*insert_wire_auditor_progress)(void *cls, | ||
830 | struct TALER_AUDITORDB_Session *session, | 886 | struct TALER_AUDITORDB_Session *session, |
831 | const struct TALER_MasterPublicKeyP *master_pub, | 887 | const struct TALER_MasterPublicKeyP *master_pub, |
832 | const char *account_name, | 888 | const struct TALER_AUDITORDB_WireProgressPoint *pp); |
833 | const struct TALER_AUDITORDB_WireProgressPoint *pp, | ||
834 | const void *in_wire_off, | ||
835 | const void *out_wire_off, | ||
836 | size_t wire_off_size); | ||
837 | 889 | ||
838 | 890 | ||
891 | /** | ||
892 | * Update information about the progress of the wire auditor. There | ||
893 | * must be an existing record for the exchange. | ||
894 | * | ||
895 | * @param cls the @e cls of this struct with the plugin-specific state | ||
896 | * @param session connection to use | ||
897 | * @param master_pub master key of the exchange | ||
898 | * @param account_name name of the wire account we are auditing | ||
899 | * @param pp where is the auditor in processing | ||
900 | * @return transaction status code | ||
901 | */ | ||
902 | enum GNUNET_DB_QueryStatus | ||
903 | (*update_wire_auditor_progress)(void *cls, | ||
904 | struct TALER_AUDITORDB_Session *session, | ||
905 | const struct TALER_MasterPublicKeyP *master_pub, | ||
906 | const struct TALER_AUDITORDB_WireProgressPoint *pp); | ||
907 | |||
839 | 908 | ||
840 | /** | 909 | /** |
841 | * Get information about the progress of the wire auditor. | 910 | * Get information about the progress of the wire auditor. |
@@ -845,20 +914,13 @@ struct TALER_AUDITORDB_Plugin | |||
845 | * @param master_pub master key of the exchange | 914 | * @param master_pub master key of the exchange |
846 | * @param account_name name of the wire account we are auditing | 915 | * @param account_name name of the wire account we are auditing |
847 | * @param[out] pp set to where the auditor is in processing | 916 | * @param[out] pp set to where the auditor is in processing |
848 | * @param[out] in_wire_off how far are we in the incoming wire transaction history | ||
849 | * @param[out] out_wire_off how far are we in the outgoing wire transaction history | ||
850 | * @param[out] wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take? | ||
851 | * @return transaction status code | 917 | * @return transaction status code |
852 | */ | 918 | */ |
853 | enum GNUNET_DB_QueryStatus | 919 | enum GNUNET_DB_QueryStatus |
854 | (*get_wire_auditor_progress)(void *cls, | 920 | (*get_wire_auditor_progress)(void *cls, |
855 | struct TALER_AUDITORDB_Session *session, | 921 | struct TALER_AUDITORDB_Session *session, |
856 | const struct TALER_MasterPublicKeyP *master_pub, | 922 | const struct TALER_MasterPublicKeyP *master_pub, |
857 | const char *account_name, | 923 | struct TALER_AUDITORDB_WireProgressPoint *pp); |
858 | struct TALER_AUDITORDB_WireProgressPoint *pp, | ||
859 | void **in_wire_off, | ||
860 | void **out_wire_off, | ||
861 | size_t *wire_off_size); | ||
862 | 924 | ||
863 | 925 | ||
864 | /** | 926 | /** |