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