aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-08-24 22:49:35 +0200
committerChristian Grothoff <christian@grothoff.org>2019-08-24 22:49:35 +0200
commit71ae493c7a7601b418de4f5c83159d46abf677b8 (patch)
tree30f4438e383326d36178ed62124ca2dac1e483fd
parentb5dd2bcdbb25cd6af1897b652c05d782a64dac5f (diff)
downloadexchange-71ae493c7a7601b418de4f5c83159d46abf677b8.tar.gz
exchange-71ae493c7a7601b418de4f5c83159d46abf677b8.zip
refactor wire auditor to properly handle multiple accounts
-rw-r--r--src/auditor/auditor.conf4
-rw-r--r--src/auditor/taler-wire-auditor.c735
-rw-r--r--src/auditor/test-auditor.conf1
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c217
-rw-r--r--src/include/taler_auditordb_plugin.h116
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?
5DB = postgres 5DB = 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?
8AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv 12AUDITOR_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;
148static struct WireAccount *wa_tail; 173static struct WireAccount *wa_tail;
149 174
150/** 175/**
151 * Handle to the wire plugin for wire operations.
152 */
153static struct TALER_WIRE_Plugin *wp;
154
155/**
156 * Name of the section that configures the account
157 * we are currently processing (matches #wp).
158 */
159static char *wp_section_name;
160
161/**
162 * Active wire request for the transaction history.
163 */
164static 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 */
169static enum GNUNET_DB_QueryStatus qsx; 178static enum GNUNET_DB_QueryStatus qsx;
@@ -174,21 +183,6 @@ static enum GNUNET_DB_QueryStatus qsx;
174static struct TALER_AUDITORDB_WireProgressPoint pp; 183static struct TALER_AUDITORDB_WireProgressPoint pp;
175 184
176/** 185/**
177 * Where we are in the inbound (CREDIT) transaction history.
178 */
179static void *in_wire_off;
180
181/**
182 * Where we are in the inbound (DEBIT) transaction history.
183 */
184static void *out_wire_off;
185
186/**
187 * Number of bytes in #in_wire_off and #out_wire_off.
188 */
189static 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 */
194static json_t *report_wire_out_inconsistencies; 188static json_t *report_wire_out_inconsistencies;
@@ -226,6 +220,11 @@ static json_t *report_row_minor_inconsistencies;
226static json_t *report_lags; 220static json_t *report_lags;
227 221
228/** 222/**
223 * Amount that is considered "tiny"
224 */
225static 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 */
231static struct TALER_Amount total_bad_amount_out_plus; 230static 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 */
633static void
634wire_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 */
670static void
671check_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 */
707static void
708conclude_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 */
811static void
812wire_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 */
855static void 917static void
856process_next_account (void *cls); 918process_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 */
863static void 927static void
864check_exchange_wire_out () 928check_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 */
1034static void 1088static void
1035process_debits () 1089process_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 */
1130static void
1131begin_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 */
1146static void
1147conclude_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 */
1169static void 1264static void
1170conclude_credit_history () 1265process_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 */
1389static void 1483static void
1390process_next_account (void *cls) 1484process_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 */
1540static void
1541begin_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 */
1553static void
1554begin_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]
2DB = postgres 2DB = postgres
3TINY_AMOUNT = TESTKUDOS:0.01
3 4
4[auditordb-postgres] 5[auditordb-postgres]
5CONFIG = postgres:///taler-auditor-test 6CONFIG = 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 */
2111static enum GNUNET_DB_QueryStatus 2131static enum GNUNET_DB_QueryStatus
2112postgres_insert_wire_auditor_progress (void *cls, 2132postgres_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 */
2151static enum GNUNET_DB_QueryStatus 2169static enum GNUNET_DB_QueryStatus
2152postgres_update_wire_auditor_progress (void *cls, 2170postgres_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 */
2190static enum GNUNET_DB_QueryStatus 2210static enum GNUNET_DB_QueryStatus
2191postgres_get_wire_auditor_progress (void *cls, 2211postgres_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 */
2265static enum GNUNET_DB_QueryStatus
2266postgres_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 */
2293static enum GNUNET_DB_QueryStatus
2294postgres_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 */
2320static enum GNUNET_DB_QueryStatus
2321postgres_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 */
109struct TALER_AUDITORDB_WireProgressPoint 109struct 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 */
124struct 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 /**