taler-auditor-sync.c (28706B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2022 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file taler-auditor-sync.c 18 * @brief Tool used by the auditor to make a 'safe' copy of the exchanges' database. 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include "exchangedb_lib.h" 23 #include "exchange-database/preflight.h" 24 #include "exchange-database/test_aml_officer.h" 25 #include "exchange-database/abort_shard.h" 26 #include "exchange-database/activate_signing_key.h" 27 #include "exchange-database/add_denomination_key.h" 28 #include "exchange-database/aggregate.h" 29 #include "exchange-database/begin_revolving_shard.h" 30 #include "exchange-database/begin_shard.h" 31 #include "exchange-database/clear_aml_lock.h" 32 #include "exchange-database/commit.h" 33 #include "exchange-database/complete_shard.h" 34 #include "exchange-database/compute_shard.h" 35 #include "exchange-database/count_known_coins.h" 36 #include "exchange-database/create_aggregation_transient.h" 37 #include "exchange-database/create_tables.h" 38 #include "exchange-database/delete_aggregation_transient.h" 39 #include "exchange-database/delete_shard_locks.h" 40 #include "exchange-database/disable_rules.h" 41 #include "exchange-database/do_check_deposit_idempotent.h" 42 #include "exchange-database/do_deposit.h" 43 #include "exchange-database/do_purse_delete.h" 44 #include "exchange-database/do_purse_deposit.h" 45 #include "exchange-database/do_purse_merge.h" 46 #include "exchange-database/do_recoup.h" 47 #include "exchange-database/do_recoup_refresh.h" 48 #include "exchange-database/do_refresh.h" 49 #include "exchange-database/do_refund.h" 50 #include "exchange-database/do_reserve_open.h" 51 #include "exchange-database/do_reserve_purse.h" 52 #include "exchange-database/do_withdraw.h" 53 #include "exchange-database/drain_kyc_alert.h" 54 #include "exchange-database/drop_tables.h" 55 #include "exchange-database/enable_rules.h" 56 #include "exchange-database/ensure_coin_known.h" 57 #include "exchange-database/event_listen_cancel.h" 58 #include "exchange-database/event_listen.h" 59 #include "exchange-database/expire_purse.h" 60 #include "exchange-database/find_aggregation_transient.h" 61 #include "exchange-database/gc.h" 62 #include "exchange-database/get_coin_denomination.h" 63 #include "exchange-database/get_coin_transactions.h" 64 #include "exchange-database/get_denomination_by_serial.h" 65 #include "exchange-database/get_denomination_info.h" 66 #include "exchange-database/get_denomination_revocation.h" 67 #include "exchange-database/get_drain_profit.h" 68 #include "exchange-database/get_expired_reserves.h" 69 #include "exchange-database/get_global_fee.h" 70 #include "exchange-database/get_global_fees.h" 71 #include "exchange-database/get_known_coin.h" 72 #include "exchange-database/get_kyc_rules.h" 73 #include "exchange-database/get_old_coin_by_h_blind.h" 74 #include "exchange-database/get_pending_kyc_requirement_process.h" 75 #include "exchange-database/get_purse_deposit.h" 76 #include "exchange-database/get_purse_request.h" 77 #include "exchange-database/get_ready_deposit.h" 78 #include "exchange-database/get_refresh.h" 79 #include "exchange-database/get_reserve_balance.h" 80 #include "exchange-database/get_reserve_by_h_planchets.h" 81 #include "exchange-database/get_reserve_history.h" 82 #include "exchange-database/get_signature_for_known_coin.h" 83 #include "exchange-database/get_unfinished_close_requests.h" 84 #include "exchange-database/get_wire_accounts.h" 85 #include "exchange-database/get_wire_fee.h" 86 #include "exchange-database/get_wire_fees.h" 87 #include "exchange-database/get_wire_hash_for_contract.h" 88 #include "exchange-database/get_withdraw.h" 89 #include "exchange-database/have_deposit2.h" 90 #include "exchange-database/inject_auditor_triggers.h" 91 #include "exchange-database/insert_active_legitimization_measure.h" 92 #include "exchange-database/insert_aml_decision.h" 93 #include "exchange-database/insert_aml_officer.h" 94 #include "exchange-database/insert_aml_program_failure.h" 95 #include "exchange-database/insert_auditor_denom_sig.h" 96 #include "exchange-database/insert_auditor.h" 97 #include "exchange-database/insert_close_request.h" 98 #include "exchange-database/insert_contract.h" 99 #include "exchange-database/insert_denomination_info.h" 100 #include "exchange-database/insert_denomination_revocation.h" 101 #include "exchange-database/insert_drain_profit.h" 102 #include "exchange-database/insert_global_fee.h" 103 #include "exchange-database/insert_kyc_failure.h" 104 #include "exchange-database/insert_kyc_requirement_process.h" 105 #include "exchange-database/insert_partner.h" 106 #include "exchange-database/insert_purse_request.h" 107 struct InsertContext; 108 #define TALER_EXCHANGEDB_REPLICATION_RESULT_CLOSURE struct InsertContext 109 #include "exchange-database/insert_records_by_table.h" 110 #include "exchange-database/insert_reserve_closed.h" 111 #include "exchange-database/insert_reserve_open_deposit.h" 112 #include "exchange-database/insert_sanction_list_hit.h" 113 #include "exchange-database/insert_signkey_revocation.h" 114 #include "exchange-database/insert_successor_measure.h" 115 #include "exchange-database/insert_wire_fee.h" 116 #include "exchange-database/insert_wire.h" 117 #include "exchange-database/iterate_active_auditors.h" 118 #include "exchange-database/iterate_active_signkeys.h" 119 #include "exchange-database/iterate_auditor_denominations.h" 120 #include "exchange-database/iterate_denomination_info.h" 121 #include "exchange-database/iterate_denominations.h" 122 #include "exchange-database/iterate_kyc_reference.h" 123 #include "exchange-database/iterate_reserve_close_info.h" 124 #include "exchange-database/kycauth_in_insert.h" 125 #include "exchange-database/kyc_provider_account_lookup.h" 126 #include "exchange-database/lookup_active_legitimization.h" 127 #include "exchange-database/lookup_aml_file_number.h" 128 #include "exchange-database/lookup_aml_history.h" 129 #include "exchange-database/lookup_aml_officer.h" 130 #include "exchange-database/lookup_auditor_status.h" 131 #include "exchange-database/lookup_auditor_timestamp.h" 132 #include "exchange-database/lookup_completed_legitimization.h" 133 #include "exchange-database/lookup_denomination_key.h" 134 #include "exchange-database/lookup_global_fee_by_time.h" 135 #include "exchange-database/lookup_h_payto_by_access_token.h" 136 #include "exchange-database/lookup_kyc_history.h" 137 #include "exchange-database/lookup_kyc_process_by_account.h" 138 #include "exchange-database/lookup_kyc_requirement_by_row.h" 139 #include "exchange-database/lookup_kyc_status_by_token.h" 140 #include "exchange-database/lookup_pending_legitimization.h" 141 #include "exchange-database/lookup_records_by_table.h" 142 #include "exchange-database/lookup_rules_by_access_token.h" 143 #include "exchange-database/lookup_serial_by_table.h" 144 #include "exchange-database/lookup_signing_key.h" 145 #include "exchange-database/lookup_signkey_revocation.h" 146 #include "exchange-database/lookup_transfer_by_deposit.h" 147 #include "exchange-database/lookup_wire_fee_by_time.h" 148 #include "exchange-database/lookup_wire_timestamp.h" 149 #include "exchange-database/lookup_wire_transfer.h" 150 #include "exchange-database/mark_refresh_reveal_success.h" 151 #include "exchange-database/persist_kyc_attributes.h" 152 #include "exchange-database/preflight.h" 153 #include "exchange-database/profit_drains_get_pending.h" 154 #include "exchange-database/profit_drains_set_finished.h" 155 #include "exchange-database/release_revolving_shard.h" 156 #include "exchange-database/reserves_get.h" 157 #include "exchange-database/reserves_get_origin.h" 158 #include "exchange-database/reserves_in_insert.h" 159 #include "exchange-database/reserves_update.h" 160 #include "exchange-database/rollback.h" 161 #include "exchange-database/select_account_merges_above_serial_id.h" 162 #include "exchange-database/select_aggregation_amounts_for_kyc_check.h" 163 #include "exchange-database/select_aggregations_above_serial.h" 164 #include "exchange-database/select_aggregation_transient.h" 165 #include "exchange-database/select_all_kyc_attributes.h" 166 #include "exchange-database/select_all_purse_decisions_above_serial_id.h" 167 #include "exchange-database/select_all_purse_deletions_above_serial_id.h" 168 #include "exchange-database/select_aml_attributes.h" 169 #include "exchange-database/select_aml_decisions.h" 170 #include "exchange-database/select_aml_measures.h" 171 #include "exchange-database/select_aml_statistics.h" 172 #include "exchange-database/select_auditor_denom_sig.h" 173 #include "exchange-database/select_batch_deposits_missing_wire.h" 174 #include "exchange-database/select_coin_deposits_above_serial_id.h" 175 #include "exchange-database/select_contract_by_purse.h" 176 #include "exchange-database/select_contract.h" 177 #include "exchange-database/select_deposit_amounts_for_kyc_check.h" 178 #include "exchange-database/select_exchange_credit_transfers.h" 179 #include "exchange-database/select_exchange_debit_transfers.h" 180 #include "exchange-database/select_exchange_kycauth_transfers.h" 181 #include "exchange-database/select_kyc_accounts.h" 182 #include "exchange-database/select_kyc_attributes.h" 183 #include "exchange-database/select_merge_amounts_for_kyc_check.h" 184 #include "exchange-database/select_purse_by_merge_pub.h" 185 #include "exchange-database/select_purse_decisions_above_serial_id.h" 186 #include "exchange-database/select_purse_deposits_above_serial_id.h" 187 #include "exchange-database/select_purse_deposits_by_purse.h" 188 #include "exchange-database/select_purse.h" 189 #include "exchange-database/select_purse_merge.h" 190 #include "exchange-database/select_purse_merges_above_serial_id.h" 191 #include "exchange-database/select_purse_requests_above_serial_id.h" 192 #include "exchange-database/select_recoup_above_serial_id.h" 193 #include "exchange-database/select_recoup_refresh_above_serial_id.h" 194 #include "exchange-database/select_refreshes_above_serial_id.h" 195 #include "exchange-database/select_refunds_above_serial_id.h" 196 #include "exchange-database/select_refunds_by_coin.h" 197 #include "exchange-database/select_reserve_closed_above_serial_id.h" 198 #include "exchange-database/select_reserve_close_info.h" 199 #include "exchange-database/select_reserve_open_above_serial_id.h" 200 #include "exchange-database/select_reserves_in_above_serial_id.h" 201 #include "exchange-database/select_wire_out_above_serial_id_by_account.h" 202 #include "exchange-database/select_wire_out_above_serial_id.h" 203 #include "exchange-database/select_withdrawals_above_serial_id.h" 204 #include "exchange-database/select_withdraw_amounts_for_kyc_check.h" 205 #include "exchange-database/set_aml_lock.h" 206 #include "exchange-database/set_purse_balance.h" 207 #include "exchange-database/start_deferred_wire_out.h" 208 #include "exchange-database/start.h" 209 #include "exchange-database/start_read_committed.h" 210 #include "exchange-database/start_read_only.h" 211 #include "exchange-database/store_wire_transfer_out.h" 212 #include "exchange-database/test_aml_officer.h" 213 #include "exchange-database/trigger_kyc_rule_for_account.h" 214 #include "exchange-database/update_aggregation_transient.h" 215 #include "exchange-database/update_auditor.h" 216 #include "exchange-database/update_kyc_process_by_row.h" 217 #include "exchange-database/update_wire.h" 218 #include "exchange-database/wad_in_insert.h" 219 #include "exchange-database/wire_prepare_data_get.h" 220 #include "exchange-database/wire_prepare_data_insert.h" 221 #include "exchange-database/wire_prepare_data_mark_failed.h" 222 #include "exchange-database/wire_prepare_data_mark_finished.h" 223 224 225 /** 226 * Handle to access the exchange's source database. 227 */ 228 static struct TALER_EXCHANGEDB_PostgresContext *src; 229 230 /** 231 * Handle to access the exchange's destination database. 232 */ 233 static struct TALER_EXCHANGEDB_PostgresContext *dst; 234 235 /** 236 * Return value from #main(). 237 */ 238 static int global_ret; 239 240 /** 241 * Main task to do synchronization. 242 */ 243 static struct GNUNET_SCHEDULER_Task *sync_task; 244 245 /** 246 * What is our target transaction size (number of records)? 247 */ 248 static unsigned int transaction_size = 512; 249 250 /** 251 * Number of records copied in this transaction. 252 */ 253 static unsigned long long actual_size; 254 255 /** 256 * Terminate once synchronization is achieved. 257 */ 258 static int exit_if_synced; 259 260 261 /** 262 * Information we track per replicated table. 263 */ 264 struct Table 265 { 266 /** 267 * Which table is this record about? 268 */ 269 enum TALER_EXCHANGEDB_ReplicatedTable rt; 270 271 /** 272 * Up to which record is the destination table synchronized. 273 */ 274 uint64_t start_serial; 275 276 /** 277 * Highest serial in the source table. 278 */ 279 uint64_t end_serial; 280 281 /** 282 * Marker for the end of the list of #tables. 283 */ 284 bool end; 285 }; 286 287 288 /** 289 * Information about replicated tables. 290 */ 291 static struct Table tables[] = { 292 { .rt = TALER_EXCHANGEDB_RT_DENOMINATIONS}, 293 { .rt = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS}, 294 { .rt = TALER_EXCHANGEDB_RT_KYC_TARGETS}, 295 { .rt = TALER_EXCHANGEDB_RT_WIRE_TARGETS}, 296 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES}, 297 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES}, 298 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES}, 299 { .rt = TALER_EXCHANGEDB_RT_RESERVES}, 300 { .rt = TALER_EXCHANGEDB_RT_RESERVES_IN}, 301 { .rt = TALER_EXCHANGEDB_RT_RESERVES_CLOSE}, 302 { .rt = TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS}, 303 { .rt = TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS}, 304 { .rt = TALER_EXCHANGEDB_RT_WITHDRAW}, 305 { .rt = TALER_EXCHANGEDB_RT_AUDITORS}, 306 { .rt = TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS}, 307 { .rt = TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS}, 308 { .rt = TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS}, 309 { .rt = TALER_EXCHANGEDB_RT_KNOWN_COINS}, 310 { .rt = TALER_EXCHANGEDB_RT_REFRESH}, 311 { .rt = TALER_EXCHANGEDB_RT_BATCH_DEPOSITS}, 312 { .rt = TALER_EXCHANGEDB_RT_COIN_DEPOSITS}, 313 { .rt = TALER_EXCHANGEDB_RT_REFUNDS}, 314 { .rt = TALER_EXCHANGEDB_RT_WIRE_OUT}, 315 { .rt = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING}, 316 { .rt = TALER_EXCHANGEDB_RT_WIRE_FEE}, 317 { .rt = TALER_EXCHANGEDB_RT_GLOBAL_FEE}, 318 { .rt = TALER_EXCHANGEDB_RT_RECOUP}, 319 { .rt = TALER_EXCHANGEDB_RT_RECOUP_REFRESH }, 320 { .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS}, 321 { .rt = TALER_EXCHANGEDB_RT_PURSE_DECISION}, 322 { .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES}, 323 { .rt = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS}, 324 { .rt = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES}, 325 { .rt = TALER_EXCHANGEDB_RT_HISTORY_REQUESTS}, 326 { .rt = TALER_EXCHANGEDB_RT_CLOSE_REQUESTS}, 327 { .rt = TALER_EXCHANGEDB_RT_WADS_OUT}, 328 { .rt = TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES}, 329 { .rt = TALER_EXCHANGEDB_RT_WADS_IN}, 330 { .rt = TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES}, 331 { .rt = TALER_EXCHANGEDB_RT_PROFIT_DRAINS}, 332 { .end = true } 333 }; 334 335 336 /** 337 * Closure for #do_insert. 338 */ 339 struct InsertContext 340 { 341 /** 342 * Table we are replicating. 343 */ 344 struct Table *table; 345 346 /** 347 * Set to error if insertion created an error. 348 */ 349 enum GNUNET_DB_QueryStatus qs; 350 }; 351 352 353 /** 354 * Function called on data to replicate in the auditor's database. 355 * 356 * @param ctx closure, a `struct InsertContext` 357 * @param td record from an exchange table 358 * @return #GNUNET_OK to continue to iterate, 359 * #GNUNET_SYSERR to fail with an error 360 */ 361 static enum GNUNET_GenericReturnValue 362 do_insert (struct InsertContext *ctx, 363 const struct TALER_EXCHANGEDB_TableData *td) 364 { 365 enum GNUNET_DB_QueryStatus qs; 366 367 if (0 >= ctx->qs) 368 return GNUNET_SYSERR; 369 qs = TALER_EXCHANGEDB_insert_records_by_table (dst, 370 td); 371 if (0 >= qs) 372 { 373 switch (qs) 374 { 375 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 376 GNUNET_assert (0); 377 break; 378 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 379 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 380 "Failed to insert record into table %d: no change\n", 381 td->table); 382 break; 383 case GNUNET_DB_STATUS_SOFT_ERROR: 384 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 385 "Serialization error inserting record into table %d (will retry)\n", 386 td->table); 387 break; 388 case GNUNET_DB_STATUS_HARD_ERROR: 389 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 390 "Failed to insert record into table %d: hard error\n", 391 td->table); 392 break; 393 } 394 ctx->qs = qs; 395 return GNUNET_SYSERR; 396 } 397 actual_size++; 398 ctx->table->start_serial = td->serial; 399 return GNUNET_OK; 400 } 401 402 403 /** 404 * Run one replication transaction. 405 * 406 * @return #GNUNET_OK on success, #GNUNET_SYSERR to rollback 407 */ 408 static enum GNUNET_GenericReturnValue 409 transact (void) 410 { 411 struct InsertContext ctx = { 412 .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT 413 }; 414 415 if (0 > 416 TALER_EXCHANGEDB_start (src, 417 "lookup src serials")) 418 return GNUNET_SYSERR; 419 for (unsigned int i = 0; ! tables[i].end; i++) 420 TALER_EXCHANGEDB_lookup_serial_by_table (src, 421 tables[i].rt, 422 &tables[i].end_serial); 423 TALER_EXCHANGEDB_rollback (src); 424 if (GNUNET_OK != 425 TALER_EXCHANGEDB_start (dst, 426 "lookup dst serials")) 427 return GNUNET_SYSERR; 428 for (unsigned int i = 0; ! tables[i].end; i++) 429 TALER_EXCHANGEDB_lookup_serial_by_table (dst, 430 tables[i].rt, 431 &tables[i].start_serial); 432 TALER_EXCHANGEDB_rollback (dst); 433 for (unsigned int i = 0; ! tables[i].end; i++) 434 { 435 struct Table *table = &tables[i]; 436 437 if (table->start_serial == table->end_serial) 438 continue; 439 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 440 "Replicating table %d from %llu to %llu\n", 441 i, 442 (unsigned long long) table->start_serial, 443 (unsigned long long) table->end_serial); 444 ctx.table = table; 445 while (table->start_serial < table->end_serial) 446 { 447 enum GNUNET_DB_QueryStatus qs; 448 449 if (GNUNET_OK != 450 TALER_EXCHANGEDB_start (src, 451 "copy table (src)")) 452 return GNUNET_SYSERR; 453 if (GNUNET_OK != 454 TALER_EXCHANGEDB_start (dst, 455 "copy table (dst)")) 456 return GNUNET_SYSERR; 457 qs = TALER_EXCHANGEDB_lookup_records_by_table (src, 458 table->rt, 459 table->start_serial, 460 &do_insert, 461 &ctx); 462 if (ctx.qs < 0) 463 qs = ctx.qs; 464 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 465 { 466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 467 "Failed to lookup records from table %d: hard error\n", 468 i); 469 global_ret = EXIT_FAILURE; 470 return GNUNET_SYSERR; 471 } 472 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 473 { 474 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 475 "Serialization error looking up records from table %d (will retry)\n", 476 i); 477 return GNUNET_SYSERR; /* will retry */ 478 } 479 if (0 == qs) 480 { 481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 482 "Failed to lookup records from table %d: no results\n", 483 i); 484 GNUNET_break (0); /* should be impossible */ 485 global_ret = EXIT_FAILURE; 486 return GNUNET_SYSERR; 487 } 488 if (0 == ctx.qs) 489 return GNUNET_SYSERR; /* insertion failed, maybe record existed? try again */ 490 TALER_EXCHANGEDB_rollback (src); 491 qs = TALER_EXCHANGEDB_commit (dst); 492 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 493 { 494 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 495 "Serialization error committing transaction on table %d (will retry)\n", 496 i); 497 continue; 498 } 499 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 500 { 501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 502 "Hard error committing transaction on table %d\n", 503 i); 504 global_ret = EXIT_FAILURE; 505 return GNUNET_SYSERR; 506 } 507 } 508 } 509 /* we do not care about conflicting UPDATEs to src table, so safe to just rollback */ 510 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 511 "Sync pass completed successfully with %llu updates\n", 512 actual_size); 513 return GNUNET_OK; 514 } 515 516 517 /** 518 * Task to do the actual synchronization work. 519 * 520 * @param cls NULL, unused 521 */ 522 static void 523 do_sync (void *cls) 524 { 525 static struct GNUNET_TIME_Relative delay; 526 527 (void) cls; 528 sync_task = NULL; 529 actual_size = 0; 530 if (GNUNET_SYSERR == 531 TALER_EXCHANGEDB_preflight (src)) 532 { 533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 534 "Failed to begin transaction with data source. Exiting\n"); 535 return; 536 } 537 if (GNUNET_SYSERR == 538 TALER_EXCHANGEDB_preflight (dst)) 539 { 540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 541 "Failed to begin transaction with data destination. Exiting\n"); 542 return; 543 } 544 if (GNUNET_OK != transact ()) 545 { 546 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 547 "Transaction failed, rolling back\n"); 548 TALER_EXCHANGEDB_rollback (src); 549 TALER_EXCHANGEDB_rollback (dst); 550 } 551 if (0 != global_ret) 552 { 553 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 554 "Transaction failed permanently, exiting\n"); 555 return; 556 } 557 if ( (0 == actual_size) && 558 (exit_if_synced) ) 559 { 560 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 561 "Databases are synchronized. Exiting\n"); 562 return; 563 } 564 if (actual_size < transaction_size / 2) 565 { 566 delay = GNUNET_TIME_STD_BACKOFF (delay); 567 } 568 else if (actual_size >= transaction_size) 569 { 570 delay = GNUNET_TIME_UNIT_ZERO; 571 } 572 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 573 "Next sync pass in %s\n", 574 GNUNET_STRINGS_relative_time_to_string (delay, 575 GNUNET_YES)); 576 sync_task = GNUNET_SCHEDULER_add_delayed (delay, 577 &do_sync, 578 NULL); 579 } 580 581 582 /** 583 * Set an option of type 'char *' from the command line with 584 * filename expansion a la #GNUNET_STRINGS_filename_expand(). 585 * 586 * @param ctx command line processing context 587 * @param scls additional closure (will point to the `char *`, 588 * which will be allocated) 589 * @param option name of the option 590 * @param value actual value of the option (a string) 591 * @return #GNUNET_OK 592 */ 593 static enum GNUNET_GenericReturnValue 594 set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 595 void *scls, 596 const char *option, 597 const char *value) 598 { 599 char **val = scls; 600 601 (void) ctx; 602 (void) option; 603 GNUNET_assert (NULL != value); 604 GNUNET_free (*val); 605 *val = GNUNET_STRINGS_filename_expand (value); 606 return GNUNET_OK; 607 } 608 609 610 /** 611 * Allow user to specify configuration file name (-s option) 612 * 613 * @param[out] fn set to the name of the configuration file 614 */ 615 static struct GNUNET_GETOPT_CommandLineOption 616 option_cfgfile_src (char **fn) 617 { 618 struct GNUNET_GETOPT_CommandLineOption clo = { 619 .shortName = 's', 620 .name = "source-configuration", 621 .argumentHelp = "FILENAME", 622 .description = gettext_noop ( 623 "use configuration file FILENAME for the SOURCE database"), 624 .require_argument = 1, 625 .processor = &set_filename, 626 .scls = (void *) fn 627 }; 628 629 return clo; 630 } 631 632 633 /** 634 * Allow user to specify configuration file name (-d option) 635 * 636 * @param[out] fn set to the name of the configuration file 637 */ 638 static struct GNUNET_GETOPT_CommandLineOption 639 option_cfgfile_dst (char **fn) 640 { 641 struct GNUNET_GETOPT_CommandLineOption clo = { 642 .shortName = 'd', 643 .name = "destination-configuration", 644 .argumentHelp = "FILENAME", 645 .description = gettext_noop ( 646 "use configuration file FILENAME for the DESTINATION database"), 647 .require_argument = 1, 648 .processor = &set_filename, 649 .scls = (void *) fn 650 }; 651 652 return clo; 653 } 654 655 656 static struct GNUNET_CONFIGURATION_Handle * 657 load_config (const char *cfgfile) 658 { 659 struct GNUNET_CONFIGURATION_Handle *cfg; 660 661 cfg = GNUNET_CONFIGURATION_create (TALER_AUDITOR_project_data ()); 662 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 663 "Loading config file: %s\n", 664 cfgfile); 665 if (GNUNET_SYSERR == 666 GNUNET_CONFIGURATION_load (cfg, 667 cfgfile)) 668 { 669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 670 "Malformed configuration file `%s', exit ...\n", 671 cfgfile); 672 GNUNET_CONFIGURATION_destroy (cfg); 673 return NULL; 674 } 675 return cfg; 676 } 677 678 679 /** 680 * Shutdown task. 681 * 682 * @param cls NULL, unused 683 */ 684 static void 685 do_shutdown (void *cls) 686 { 687 (void) cls; 688 if (NULL != sync_task) 689 { 690 GNUNET_SCHEDULER_cancel (sync_task); 691 sync_task = NULL; 692 } 693 } 694 695 696 /** 697 * Initial task. 698 * 699 * @param cls NULL, unused 700 */ 701 static void 702 run (void *cls) 703 { 704 (void) cls; 705 706 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 707 NULL); 708 sync_task = GNUNET_SCHEDULER_add_now (&do_sync, 709 NULL); 710 } 711 712 713 /** 714 * Setup plugins in #src and #dst and #run() the main 715 * logic with those plugins. 716 */ 717 static void 718 setup (struct GNUNET_CONFIGURATION_Handle *src_cfg, 719 struct GNUNET_CONFIGURATION_Handle *dst_cfg) 720 { 721 src = TALER_EXCHANGEDB_connect (src_cfg); 722 if (NULL == src) 723 { 724 global_ret = EXIT_NOTINSTALLED; 725 return; 726 } 727 dst = TALER_EXCHANGEDB_connect (dst_cfg); 728 if (NULL == dst) 729 { 730 global_ret = EXIT_NOTINSTALLED; 731 TALER_EXCHANGEDB_disconnect (src); 732 src = NULL; 733 return; 734 } 735 GNUNET_SCHEDULER_run (&run, 736 NULL); 737 TALER_EXCHANGEDB_disconnect (src); 738 src = NULL; 739 TALER_EXCHANGEDB_disconnect (dst); 740 dst = NULL; 741 } 742 743 744 /** 745 * The main function of the taler-auditor-exchange tool. This tool is used 746 * to add (or remove) an exchange's master key and base URL to the auditor's 747 * database. 748 * 749 * @param argc number of arguments from the command line 750 * @param argv command line arguments 751 * @return 0 ok, non-zero on error 752 */ 753 int 754 main (int argc, 755 char *const *argv) 756 { 757 char *src_cfgfile = NULL; 758 char *dst_cfgfile = NULL; 759 char *level = GNUNET_strdup ("WARNING"); 760 struct GNUNET_CONFIGURATION_Handle *src_cfg; 761 struct GNUNET_CONFIGURATION_Handle *dst_cfg; 762 const struct GNUNET_GETOPT_CommandLineOption options[] = { 763 GNUNET_GETOPT_option_mandatory ( 764 option_cfgfile_src (&src_cfgfile)), 765 GNUNET_GETOPT_option_mandatory ( 766 option_cfgfile_dst (&dst_cfgfile)), 767 GNUNET_GETOPT_option_help ( 768 TALER_AUDITOR_project_data (), 769 gettext_noop ("Make a safe copy of an exchange database")), 770 GNUNET_GETOPT_option_uint ( 771 'b', 772 "batch", 773 "SIZE", 774 gettext_noop ( 775 "target SIZE for a the number of records to copy in one transaction"), 776 &transaction_size), 777 GNUNET_GETOPT_option_flag ( 778 't', 779 "terminate-when-synchronized", 780 gettext_noop ( 781 "terminate as soon as the databases are synchronized"), 782 &exit_if_synced), 783 GNUNET_GETOPT_option_version (VERSION), 784 GNUNET_GETOPT_option_loglevel (&level), 785 GNUNET_GETOPT_OPTION_END 786 }; 787 788 TALER_gcrypt_init (); /* must trigger initialization manually at this point! */ 789 { 790 int ret; 791 792 ret = GNUNET_GETOPT_run ("taler-auditor-sync", 793 options, 794 argc, argv); 795 if (GNUNET_NO == ret) 796 return EXIT_SUCCESS; 797 if (GNUNET_SYSERR == ret) 798 return EXIT_INVALIDARGUMENT; 799 } 800 GNUNET_assert (GNUNET_OK == 801 GNUNET_log_setup ("taler-auditor-sync", 802 level, 803 NULL)); 804 GNUNET_free (level); 805 /* suppress compiler warnings... */ 806 GNUNET_assert (NULL != src_cfgfile); 807 GNUNET_assert (NULL != dst_cfgfile); 808 if (0 == strcmp (src_cfgfile, 809 dst_cfgfile)) 810 { 811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 812 "Source and destination configuration files must differ!\n"); 813 return EXIT_INVALIDARGUMENT; 814 } 815 src_cfg = load_config (src_cfgfile); 816 if (NULL == src_cfg) 817 { 818 GNUNET_free (src_cfgfile); 819 GNUNET_free (dst_cfgfile); 820 return EXIT_NOTCONFIGURED; 821 } 822 dst_cfg = load_config (dst_cfgfile); 823 if (NULL == dst_cfg) 824 { 825 GNUNET_CONFIGURATION_destroy (src_cfg); 826 GNUNET_free (src_cfgfile); 827 GNUNET_free (dst_cfgfile); 828 return EXIT_NOTCONFIGURED; 829 } 830 setup (src_cfg, 831 dst_cfg); 832 GNUNET_CONFIGURATION_destroy (src_cfg); 833 GNUNET_CONFIGURATION_destroy (dst_cfg); 834 GNUNET_free (src_cfgfile); 835 GNUNET_free (dst_cfgfile); 836 837 return global_ret; 838 } 839 840 841 /* end of taler-auditor-sync.c */