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