|
22 | 22 | #include "Controller.h" |
23 | 23 | #include "Json/Json.h" |
24 | 24 | #include "Logger.h" |
| 25 | +#include "Rpa.h" |
25 | 26 | #include "ServerMisc.h" |
26 | 27 | #include "Servers.h" |
27 | 28 | #include "Storage.h" |
@@ -521,6 +522,15 @@ void App::parseArgs() |
521 | 522 | " option only takes effect on initial sync, otherwise this option has no effect.\n"), |
522 | 523 | QString("MB"), |
523 | 524 | }, |
| 525 | + { |
| 526 | + "rpa", |
| 527 | + QString("Explicitly enable the Reusable Payment Address index and offer the associated \"blockchain.rpa.*\" RPC" |
| 528 | + " methods to clients. To explicitly disable this facility, use the CLI arg --no-rpa. Default is: %1.\n") |
| 529 | + .arg(options->rpa.enabledSpecToString()) |
| 530 | + }, |
| 531 | + { |
| 532 | + "no-rpa", QString("<hidden>") |
| 533 | + }, |
524 | 534 | { |
525 | 535 | "dump-sh", |
526 | 536 | QString("*** This is an advanced debugging option *** Dump script hashes. If specified, after the database" |
@@ -554,6 +564,13 @@ void App::parseArgs() |
554 | 564 | }); |
555 | 565 | } |
556 | 566 |
|
| 567 | + // Hide options that we marked above as hidden by setting the description to: "<hidden>" |
| 568 | + for (auto & opt : allOptions) { |
| 569 | + if (opt.description() == "<hidden>") { |
| 570 | + opt.setFlags(opt.flags() | QCommandLineOption::HiddenFromHelp); |
| 571 | + } |
| 572 | + } |
| 573 | + |
557 | 574 | parser.addOptions(allOptions); |
558 | 575 | QString configArgDesc = "Configuration file (optional). To read configuration variables from the environment instead, "; |
559 | 576 | #ifdef Q_OS_LINUX |
@@ -1379,6 +1396,90 @@ void App::parseArgs() |
1379 | 1396 | DebugM("config: pidfile = ", options->pidFileAbsPath, " (size: ", QFileInfo(options->pidFileAbsPath).size(), " bytes)"); |
1380 | 1397 | }); |
1381 | 1398 | } |
| 1399 | + |
| 1400 | + // CLI: --rpa |
| 1401 | + // conf: rpa |
| 1402 | + if (const bool psetYes = parser.isSet("rpa"), psetNo = parser.isSet("no-rpa"); psetYes || psetNo || conf.hasValue("rpa")) { |
| 1403 | + bool val{}; |
| 1404 | + if (!psetYes && !psetNo) { |
| 1405 | + bool ok{}; |
| 1406 | + val = conf.boolValue("rpa", false, &ok); |
| 1407 | + if (!ok) throw BadArgs("rpa: bad value. Specify a boolean value such as 0, 1, true, false, yes, no"); |
| 1408 | + } |
| 1409 | + else if (psetYes && psetNo) throw BadArgs("Cannot specify --rpa and --no-rpa at the same time!"); |
| 1410 | + else val = psetYes; // will be false if psetNo here |
| 1411 | + options->rpa.enabledSpec = val ? Options::Rpa::Enabled : Options::Rpa::Disabled; |
| 1412 | + Util::AsyncOnObject(this, [val] { DebugM("config: rpa = ", val); }); |
| 1413 | + } |
| 1414 | + |
| 1415 | + // conf: rpa_max_history |
| 1416 | + if (conf.hasValue("rpa_max_history")) { |
| 1417 | + bool ok; |
| 1418 | + int mh = conf.intValue("rpa_max_history", -1, &ok); |
| 1419 | + if (!ok || mh < options->maxHistoryMin || mh > options->maxHistoryMax) |
| 1420 | + throw BadArgs(QString("rpa_max_history: bad value. Specify a value in the range [%1, %2]") |
| 1421 | + .arg(options->maxHistoryMin).arg(options->maxHistoryMax)); |
| 1422 | + options->rpa.maxHistory = mh; |
| 1423 | + // log this later in case we are in syslog mode |
| 1424 | + Util::AsyncOnObject(this, [mh]{ Debug() << "config: rpa_max_history = " << mh; }); |
| 1425 | + } else { |
| 1426 | + // Otherwise, if nothing specified, we have special logic here: |
| 1427 | + // We inherit whatever the user specified for max_history, if anything (may be default) |
| 1428 | + options->rpa.maxHistory = options->maxHistory; |
| 1429 | + if (conf.hasValue("max_history")) { |
| 1430 | + Util::AsyncOnObject(this, [mh = options->maxHistory]{ |
| 1431 | + Debug() << "config: rpa_max_history = " << mh << " (inherited from max_history)"; |
| 1432 | + }); |
| 1433 | + } |
| 1434 | + } |
| 1435 | + |
| 1436 | + // conf: rpa_history_block_limit / rpa_history_blocks |
| 1437 | + if (const bool b1 = conf.hasValue("rpa_history_blocks"), b2 = conf.hasValue("rpa_history_block_limit"); b1 || b2) { |
| 1438 | + // support either: "rpa_history_block_limit" or "rpa_history_blocks", but not both |
| 1439 | + if (b1 && b2) throw BadArgs("Both `rpa_history_blocks` and `rpa_history_block_limit` were found in the config file; this looks like a typo."); |
| 1440 | + const QString confKey(b1 ? "rpa_history_blocks" : "rpa_history_block_limit"); |
| 1441 | + bool ok; |
| 1442 | + const int limit = conf.intValue(confKey, -1, &ok); |
| 1443 | + if (!ok || limit < 0 || unsigned(limit) < options->rpa.historyBlockLimitMin || unsigned(limit) > options->rpa.historyBlockLimitMax) |
| 1444 | + throw BadArgs(QString("%1: bad value. Specify a value in the range [%2, %3]") |
| 1445 | + .arg(confKey).arg(options->rpa.historyBlockLimitMin).arg(options->rpa.historyBlockLimitMax)); |
| 1446 | + options->rpa.historyBlockLimit = unsigned(limit); |
| 1447 | + // log this later in case we are in syslog mode |
| 1448 | + Util::AsyncOnObject(this, [limit, confKey]{ Debug() << "config: " << confKey << " = " << limit; }); |
| 1449 | + } |
| 1450 | + |
| 1451 | + // conf: rpa_prefix_bits_min |
| 1452 | + static_assert(Options::Rpa::defaultPrefixBitsMin >= Rpa::PrefixBitsMin && Options::Rpa::defaultPrefixBitsMin <= Rpa::PrefixBits |
| 1453 | + && !(Options::Rpa::defaultPrefixBitsMin & 0b11)); |
| 1454 | + if (conf.hasValue("rpa_prefix_bits_min")) { |
| 1455 | + bool ok; |
| 1456 | + int pbm = conf.intValue("rpa_prefix_bits_min", -1, &ok); |
| 1457 | + if (!ok || pbm < int(Rpa::PrefixBitsMin) || pbm > int(Rpa::PrefixBits) || pbm & 0b11 /* fancy way to check if multiple of 4 */) { |
| 1458 | + throw BadArgs(QString("rpa_prefix_bits_min: bad value. Specify a number that is a multiple of 4 and that is in the range [%1, %2].") |
| 1459 | + .arg(Rpa::PrefixBitsMin).arg(Rpa::PrefixBits)); |
| 1460 | + } |
| 1461 | + options->rpa.prefixBitsMin = pbm; |
| 1462 | + // log this later in case we are in syslog mode |
| 1463 | + Util::AsyncOnObject(this, [pbm]{ Debug() << "config: rpa_prefix_bits_min = " << pbm; }); |
| 1464 | + } |
| 1465 | + |
| 1466 | + // conf: rpa_start_height |
| 1467 | + if (const auto b1 = conf.hasValue("rpa_start_height"), b2 = conf.hasValue("rpa_starting_height"); b1 || b2) { |
| 1468 | + // support either: "rpa_start_height" or "rpa_starting_height", but not both |
| 1469 | + if (b1 && b2) throw BadArgs("Both `rpa_start_height` and `rpa_starting_height` were found in the config file; this looks like a typo."); |
| 1470 | + const QString confKey(b1 ? "rpa_start_height" : "rpa_starting_height"); |
| 1471 | + bool ok; |
| 1472 | + int ht = conf.intValue(confKey, -1, &ok); |
| 1473 | + if (!ok || ht < -1 /* -1 ok, -2 not, etc*/ || (ht >= 0 && ht > int(Storage::MAX_HEADERS))) |
| 1474 | + throw BadArgs(QString("%1: bad value. Specify a block height between [0, %2], or use -1 to" |
| 1475 | + " auto-configure this setting with a chain-specific default (%3 for mainnet, %4 for" |
| 1476 | + " all other nets).") |
| 1477 | + .arg(confKey).arg(Storage::MAX_HEADERS).arg(Options::Rpa::defaultStartHeightForMainnet) |
| 1478 | + .arg(Options::Rpa::defaultStartHeightOtherNets)); |
| 1479 | + options->rpa.requestedStartHeight = ht; |
| 1480 | + // log this later in case we are in syslog mode |
| 1481 | + Util::AsyncOnObject(this, [ht, confKey]{ Debug() << "config: " << confKey << " = " << ht; }); |
| 1482 | + } |
1382 | 1483 | } |
1383 | 1484 |
|
1384 | 1485 | namespace { |
|
0 commit comments